android 内存泄漏代码,记一次Android内存泄漏的优化经历

原标题:记一次Android内存泄漏的优化经历

本文作者

作者:黄俊彬

链接:

https://www.jianshu.com/p/c8e691a69086

本文由作者授权发布。

文章不难,但为真实的一次优化经历,值得借鉴。

1

背景

通过线上收集的日志分析,存在部分OOM的日志,故通过leakcanary进行内存泄漏追踪。

引用链日志

在开发的过程中,leakcanary报出了内存泄漏,详细的日志如下:

d0619faf6f7610203ed9e8e4ee80c0d9.png

并且全局有其他Activity也存在相同引用链的内存泄漏,日志如下:

5c39da6d057d80071328bb6480003ff0.png

使用MAT进行分析,引用链也相同,日志如下:

c2d0517e76487b65c9844bf95021ba90.png

影响:

通过AS自带的Profiler进行分析,发现此内存泄漏非常严重,进入多次Activity,页面Finish掉后,GC均无法进行回收,实例会一直存在。这样如果用户多次操作页面,那么很容易触发OOM的异常。

a04b0be64cde17013baca07496378b25.png

2

分析

FileMainActivity大致的结构如下,一个Activity里面,包含了一个Fragment,Fragment是一个列表。

通过引用链可以发现为ViewRootImpl$ViewRootHandler导致Activity没有回收。初步怀疑是否由于handler导致。但通过排查FileMainActivity代码,内部的handler是使用static内部类,同时也使用了软引用持有,并没有导致触发的原因。

通过搜索引擎,也无相关的博文介绍。问题一度陷入停滞。

但鉴于问题的严重性,决定采用排除法进行验证,当然过程耗时长,主要的思路如下:

1、Activity里面不集成Fragment,然后运行,重复进入退出,分析GC,发现不会存在内存泄漏;

(问题初步定为为Fragment里的代码存在内存泄漏)

2、恢复Fragment代码,onActivityCreate中的代码大致为,初始化控件、请求网络数据、显示列表。通过依次屏蔽3个方法,再进入验证

(问题发现在屏蔽了显示列表的方法后,不会存在内存泄漏。问题定位在显示列表的方法中)

3、通过依次屏蔽显示列表的方法中,定位问题出在一句代码,引起了内存泄漏

mPullToRefreshLayout.refreshComplete();

4、mPullToRefreshLayout是一个第三方的下拉刷新控件,PtrFrameLayout。refreshComplete的源码如下:

https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh

finalpublicvoidrefreshComplete(){

if(DEBUG) {

PtrCLog.i(LOG_TAG, "refreshComplete");

}

if(mRefreshCompleteHook != null) {

mRefreshCompleteHook.reset();

}

intdelay = ( int) (mLoadingMinTime - (System.currentTimeMillis() - mLoadingStartTime));

if(delay <= 0) {

if(DEBUG) {

PtrCLog.d(LOG_TAG, "performRefreshComplete at once");

}

performRefreshComplete();

} else{

postDelayed( newMyRunnable( this, 1), delay);

if(DEBUG) {

PtrCLog.d(LOG_TAG, "performRefreshComplete after delay: %s", delay);

}

}

}

5、里面存在关键代码postDelayed,故怀疑可能此处代码产生内存泄漏。通过断点打印发现如下:

8e406d598e6f16630adb6e325adc235c.png

最终定位问题如下:

由于PtrFrameLayout的refreshComplete方法中的postDelayed导致了内存泄漏,由于delay很长,导致Activity不会被回收。

3

处理

几经波折,终于定位到问题。那么现在就好处理了。通过分析我们发现这里主要的问题就是delay值很大导致。我们分析发现如下代码:

intdelay = ( int)

(mLoadingMinTime - (System.currentTimeMillis() - mLoadingStartTime));

发现了long强制转成了int,这里面导致了数据溢出,从而影响了delay最后的运算。这里通过如下处理则可修复内存泄漏的问题:

13a290f228fac580adc62d1ae971d313.png

修复后,通过proflier分析,Activity已正常被GC回收,至此解决问题。

结论

1、分析内存泄漏需要多用工具,leakcanary、AS自带的Profile及Mat工具

2、需要耐心及细心,优化内存泄漏是一个挺麻烦,但也很重要的事情

Android性能优化-内存泄漏(上)

https://www.jianshu.com/p/402225fce4b2

Android性能优化-内存泄漏(下)

https://www.jianshu.com/p/2c9fc4e871a4返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值