记一次Android内存泄漏的优化经历
2020/2/28 23:15:20
本文主要是介绍记一次Android内存泄漏的优化经历,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
问题
背景
通过线上收集的日志分析,存在部分OOM的日志,故通过leakcanary进行内存泄漏追踪。
引用链日志
在开发的过程中,leakcanary报出了内存泄漏,详细的日志如下:
并且全局有其他Activity也存在相同引用链的内存泄漏,日志如下:
使用MAT进行分析,引用链也相同,日志如下:
影响
通过AS自带的Profiler进行分析,发现此内存泄漏非常严重,进入多次Activity,页面Finish掉后,GC均无法进行回收,实例会一直存在。这样如果用户多次操作页面,那么很容易触发OOM的异常。
分析
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的源码如下:
/** * Call this when data is loaded. * The UI will perform complete at once or after a delay, depends on the time elapsed is greater then {@link #mLoadingMinTime} or not. */ final public void refreshComplete() { if (DEBUG) { PtrCLog.i(LOG_TAG, "refreshComplete"); } if (mRefreshCompleteHook != null) { mRefreshCompleteHook.reset(); } int delay = (int) (mLoadingMinTime - (System.currentTimeMillis() - mLoadingStartTime)); if (delay <= 0) { if (DEBUG) { PtrCLog.d(LOG_TAG, "performRefreshComplete at once"); } performRefreshComplete(); } else { postDelayed(new MyRunnable(this, 1), delay); if (DEBUG) { PtrCLog.d(LOG_TAG, "performRefreshComplete after delay: %s", delay); } } } 复制代码
5、里面存在关键代码postDelayed,故怀疑可能此处代码产生内存泄漏。通过断点打印发现如下:
最终定位问题如下: 由于PtrFrameLayout的refreshComplete方法中的postDelayed导致了内存泄漏,由于delay很长,导致Activity不会被回收。
处理
几经波折,终于定位到问题。那么现在就好处理了。通过分析我们发现这里主要的问题就是delay值很大导致。我们分析发现如下代码
int delay = (int) (mLoadingMinTime - (System.currentTimeMillis() - mLoadingStartTime)); 复制代码
发现了long强制转成了int,这里面导致了数据溢出,从而影响了delay最后的运算。这里通过如下处理则可修复内存泄漏的问题:
修复后,通过proflier分析,Activity已正常被GC回收,至此解决问题。
结论
1、分析内存泄漏需要多用工具,leakcanary、AS自带的Profile及Mat工具
2、需要耐心及细心,优化内存泄漏是一个挺麻烦,但也很重要的事情
推荐
关于
欢迎关注我的个人公众号
微信搜索:一码一浮生,或者搜索公众号ID:life2code
这篇关于记一次Android内存泄漏的优化经历的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-01-18android.permission.read_media_video
- 2024-01-18android_getaddrinfo failed eai_nodata
- 2024-01-18androidmo
- 2024-01-15Android下三种离屏渲染技术
- 2024-01-09Android 蓝牙使用
- 2024-01-06Android对接华为AI - 文本识别
- 2023-11-15代码安全之代码混淆及加固(Android)
- 2023-11-10简述Android语音播报TTS
- 2023-11-06Android WiFi工具类
- 2023-07-22Android开发未来的出路