tjnhfht的博客

最近app的oom异常比较多,重点要求解决oom的bug,所以着重研究了一下eclipse中的mat分析内存的方法。

针对阅读页的分析比较繁琐,代码也比较多,不多说了,下面记录一下起始页ActLoading的内存分析及解决方案:

1.首先,在onDestroy中放一个System.gc();方法来提醒虚拟机进行内存回收,然后我们就可以在每次进出这个Activity的时候观察logcat中的情况,GC_EXPLICIT 这个表示调用System.gc时产生的内存回收:

GC_EXPLICIT freed 3502K, 41% free 54633K/91060K, paused 3ms+9ms, total 86ms,

上面的代码中就是调用关闭这个Activity的时候onDestroy中回收的日志,我重点看的是这个空闲的百分比(41%)和后面的总共分配的堆内存空间(91060K),反复进出后这个百分比越来越小或者总空间变大,证明有泄露的嫌疑。

2.反复进出几次,生成内存分析文件,过程不多说了,直接看图:

每个人都有自己的一套分析方法,我自己的方法是以直方图为主的:

因为要分析自己的写的类,所以先根据包名分一下类,方便查找自己的Activity。

很容易的找到这个Activity代码了,发现退出以后还存在8个Activity对象,下面要分析这个对象为啥没有被回收掉了:

一个对象在gc的时候没有被回收说明它在通往GC根节点的路径上有其他的引用。

右键这个类,找它到GC根节点之间所有的排除软引用,弱引用,虚引用的其他引用。

可以看到有两个原因使它不能被回收;一个线程,一个就是我们公司自己的开发的一个app统计sdk。

这里面的线程是不是一个主要原因,因为它只是延迟了我们的内存释放,并不会一直占用,,当到一定的时间后,线程执行完毕,会自己回收掉的,但是我们并不能不管它,因为QA在测试的时候,不会给你足够的时间来回收这些耗时间的线程。

那么到底是哪里的线程呢,分析了一下代码整个Activity里面只有了一个网络请求:

那么内存泄露的点就有可能在这里,其实可以粗略的判断一下,这个是不是泄露点,那就是先把这个方法注释掉,重复以上的步骤,看看上面的线程泄露还在不在。如果注释以后,问题不在了,那么它就是我们重点解决的对象;

上面的测试看到,原来的线程泄露不在了,那么那个网络请求的方法到底有什么问题呢?

在于参数用到了LoginUtils.getSessionId(),而不是一个单纯的string,我修改一下这个方法:

上面的线程泄露问题就解决了。

至于第二个内存泄露的问题analysis.collect.DatabaseAdapater:是由于自家公司的统计sdk占用了第一次赋予的Activity实例,而不能被回收,我还无能为力,只能依靠sdk修改了。。。。

内存分析方法多多,我只是列举了自己摸索的一套分析方式而已

不敢接受失败的人,往往是那些追求完美的人,

tjnhfht的博客

相关文章:

你感兴趣的文章:

标签云: