这一次,我优化了37%的内存

话说,从mta上报的数据上来看,我们的app出现了3起OOM(out of memery):

java.lang.Throwable: java.lang.OutOfMemoryError
	at com.tencent.stat.a.d.(Unknown Source)
	at com.tencent.stat.g.uncaughtException(Unknown Source)
	at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
	at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
	at dalvik.system.NativeStart.main(Native Method)

从错误堆栈是显然是看不出任何问题的,那么问题会出现在什么地方呢?

我们猜测了一下几种可能?

1、存在内存泄露。

2、不需要的bitmap没有被释放。

那么问题是否就是上面这两种情况呢?

带着这个问题,我们首先验证下,内存是否占用真的很大。

首先,开启android studio内存占用图标展示工具,可以看到内存占用77M,

重启应用,各页面点击一下,相关路径踩一踩,不踩不知道,一踩就吓一跳,启动的时候,直观的从图中可以看到,内存占用40M,然而,切换到发现tab,发现内存彪到70M,然后,切换其他页面,如下图:

比如切换到,消息,我的,等等,发现内存依然,居高不下了,滑动发现页的时候,内存占用依然有标高的趋势。

我们使用 dumpsys meminfo com.xxx.xxx (app包名),查看内存占用情况如下图:

cat 一下进程,可以看到最大占用(这里包括虚拟机和原生)如下图:

不用说了,这个的优化,那么怎么办?

依然是寄出我们android studio上的内存分析工具,如下图:

首先,GC一下 ,然后在导出hprof文件,进行分析 。首先分析是否存在内存泄露:

如上图,并没有发现有内存泄露的activity存在,这也归功于我们平常有事没事都会随手分析一下是否有内存泄露,如果有,早就解决了,等不到我。

那么既然没有内存泄露的Activity,那么我们何不看一下对象的内存占用情况呢?

如是:如图

这里,我们很轻易的抓住了第一个凶手,bitmap。

其原因是因为这里做了一个打分的自定义view,这个view的分数是绘制出来的,之所以没有用字体,是因为引入一个字体库会增加包大小(虽然可以有些工具可以抽取仅仅需要的字体元素来缩小字体库,但我们考虑到实现一个打分效果的自定义view的成本也不大,因此并没有考虑抽取字体库),得不偿失,然而,这个自定义view中每个实例,都拥有0到9加上。的bitmap;

然而他被显示到列表的时候,可想而知,会有多少张图,优化起来相当简单,将这些bitmap使用静态变量保存,这样所有实例只会公用一份bitmap列表了:

,好吧,继续走查其他对象的内存占用,我们发现:

PopoFeed对象占用内存也较多:但,一层一层的剥下去,最终发现是PopoFeed对象中的User对象里面的UserTag占用内存较多:

可以想象,一个popofeed如果有20多条评论,10几个人打分,那这样就有30个User对象在popofeed对象中,30*3K,那就是90K,这些对view展示无用的数据吃内存也是非常恐怖的,所以,拉起后台同学,对返回的数据做了优化。同时,我们发现,返回的数据多,GSON转model所需要的内存也较多,所以,服务端对返回数据做清洗还是挺有必要的。

,好吧,到了第三阶段,我们继续走查,发现fragment占用内存较多,其实不难推测,使用fragmentManger管理fragment ,你看到的是一个页面,但其实上,默认是会加载1-2个到缓存中的,从源码中可以看出:

所以,你当前在发现页,实际上,大厅,消息都已经加载进内存了,那么这时候的做法就是在重写setUserVisibleHint

方法,当fragment可见的时候,将数据渲染到view上,当fragment不可见的时候,把view上数据清理掉,不过或许也有更好的方法,如果有,欢迎告诉我~。

然而,还有一个更加可恶的问题,那就是当fragment执行onDestroyView方法后,该fragment并没有释放掉内存,这也就是为什么切换到发现之后,在切换其他fragment内存居高不下的首要原因,我的解决办法是:

因为从引用树上看到:

findFragment被fragmentManger引用着,其在执行onDestroyView的时候,一些该释放的内存得不到释放,因此采取以上办法。

好吧,经过三个小小的优化,我们来看看,内存占用:

对比发现页:

发现页内存占用现在是 48M,同比之前的77M,减少了37%。

然后切换到我的

我们发现内存占用只有28.58M。

对于内存峰值方面的对比,

(165516-120792)/165516 = 27%

总结这次的优化:

1、当内存中类的多个对象引用的资源不变的时候,请使用静态,这样,这些资源就只有一份,减少不必要的内存占用。

2、json转model是一个很耗时的过程,减少json中不必要的字段,不仅可以加快json转model的时间,还能降低内存占用。

3、fragment不可见的时候,实际上可能还占用着你的内存,要懂得小心释放不必要的内存。

腾讯自主研发,荣获2015年十佳组件第一名的“tMemoryMonitor”内存泄漏分析工具。该腾讯内部工具已经在腾讯WeTest官网内免费开放给用户使用

TMM下载地址:http://wetest.qq.com/cloud/index.php/index/TMM

【工具简介】

tMemoryMonitor简称TMM,是一款运行时C/C++内存泄漏检测工具。TMM认为在进程退出时,内存中没有被释放且没有指针指向的无主内存块即为内存泄漏,并进而引入垃圾回收机制,在进程退出时检测出堆内存中所有没有被引用的内存单元,因而内存泄漏检测准确率为100%。

时间: 2024-12-29 06:51:08

这一次,我优化了37%的内存的相关文章

Android app性能优化大汇总之内存性能优化

写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在Android开发中遇到关于内存问题,或者马上要参加面试,或者就是单纯的学习或复习一下内存相关知识,都欢迎阅读.(本文最后我会尽量列出所参考的文章). 内存简介: RAM(random access memory)随机存取存储器.说白了就是内存. 一般Java在内存分配时会涉及到以下区域: 寄存器(R

Android优化-与Java有关-内存

内存优化 Android系统对每个软件所能使用的RAM空间进行了限制(如:Nexus one 对每个软件的内存限制是24M),同时Java语言本身比较消耗内存,dalvik虚拟机也要占用一定的内存空间,所以合理使用内存,彰显出一个程序员的素质和技能. 1) 了解JIT 即时编译(Just-in-time Compilation,JIT),又称动态转译(Dynamic Translation),是一种通过在运行时将字节码翻译为机器码,从而改善字节码编译语言性能的技术.即时编译前期的两个运行时理论是

java程序性能优化之找出内存溢出元凶

我曾经在刚入行的时候做过一个小的swing程序,用到了java SE,swing,Thread等东东,当初经验少也没有做过严格的性能测试,布到生产环境用了一段时间后发现那个小程序有时候会抛java.lang.OutOfMemoryError异常,就是java的内存溢出.当时也上网查了不少资料,试过一些办法,代码也稍微做了些优化,但是有一个问题我始终是找不到解决的方案 - 不知为什么子窗体关闭后java的垃圾回收机制无法回收其资源,因为这个程序可能要经常开关一些子窗体,那么这些子窗体关闭后无法释放

【好书摘要】性能优化中CPU、内存、磁盘IO、网络性能的依赖

系统优化是一项复杂.繁琐.长期的工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采集.评估.监测,而且是一个长期和持续的过程,不 是说现在优化了,测试了,以后就可以一劳永逸了,也不是说书本上的优化就适合眼下正在运行的系统,不同的系统.不同的硬件.不同的应用优化的重点也不同. 优化的方法也不同.优化的参数也不同.性能监测是系统优化过程中重要的一环,如果没有监测.不清楚性能瓶颈在哪里,怎么优化呢?所以找到性能 瓶颈是性能监测的目的,也是系统优化的关键.系统由若干子系统构成,通常修改一个子系

android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存

经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目  Android-Universal-Image-Loader  或者 ignition 都是个很好的选择. 在这里把原来 写过的优化的代码直接拿出来,经过测试千张图片效果还是不错的. 免费培训课:http://www.jinhusns.com/Products/Curriculum/?type=xcj 工程目录 至于 Activity 就是加载了 1个网格布局 01./** 02.*   实现 异步加载 和   2级缓

Java集群优化——必须了解的内存溢出与内存泄露

概念: 内存溢出 out of memory 是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. 内存泄露 memory leak 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光. 联系: memory leak会最终会导致out of memory,内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满

优化—对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常.所以,对于图片的内存优化,是Android应用开发中比较重要的内容. 1) 要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间.那为什么还需

如何优化Cocos2d-X游戏的内存

在游戏项目优化中都会碰到一个问题,如何既能减少内存又能尽量减少包的大小?在实际项目中有些经验分享一下,事实上2D游戏中最占内存的就是图片资源,一张图片使用不同的纹理格式带来的性能差异巨大,下表是我在IOS平台一个小Demo中的测试结果,该Demo的原始内存占用是7M,测试方法是一次性加载5张2048*2048的图片,使用TexturePacker工具生成图片,内存统计使用Instrument工具,加载时间统计用-X引擎提供的CCTime类,单位是微秒. 图片格式               加载

如何优化cocos2d程序的内存使用和程序大小

在我完成第一个游戏项目的时候,我深切地意识到"使用cocos2d来制作游戏的开发者们,他们大多会被cocos2d的内存问题所困扰".而我刚开始接触cocos2d的时候,社区里面的人们讨论了一个非常有意义的话题:"请简单地讲述你认为新手cocos2d程序员在他开始编码之前,最应该先知道,或者应该关注和注意的事项."这个问题的答案很多,有人讲是"如何加载和保存游戏数据",有人讲的是"如何实现有限状态机"等等.而最吸引我的则是,有一