本文包括四章内容:一、Android OOM类型;二、OOM分析工具;三、OOM实例问题分析定位;四、参考资源
一、Android OOM类型
在Android平台上常见的OOM有如下几种:
1、使用static修饰Context变量,Context被Hold住了导致Activity无法销毁,在之前的Android Context源码解析中有提及这一情况。
2、Bitmap没有及时回收,调用recycle()函数并不能立即释放Bitmap,读取Bitmap到内存的时候没有做采样率的设置;
3、线程数超限,proc/pid/status中记录的线程数超过proc/sys/kernel/threads-max中规定的最大线程数,场景如随意创建线程,没有使用线程池来管理;
4、文件描述符(fd)超限,proc/pid/fd下文件数目超过proc/pid/limits中的限制,场景如大量的Socket请求或者文件打开操作。
5、Cursor使用问题,使用完之后没有及时关闭。
6、Java堆内存超限,申请的堆内存超过Runtime.getRuntime().maxMemory()。
7、Adapter没使用缓存的convertView;
8、广播注册之后没有反注册;
9、WebView没有销毁,应该调用destroy()函数去销毁;
10、数组内对象过多,没有及时清理。
11、本文要详细介绍的,Handler使用不当导致。
二、OOM分析工具
前几天客户反馈一个OOM问题,实际路测中地图多次偏航之后出现OOM异常退出,由于服务器没有相应版本的混淆映射Mapping文件,无法准确定位问题代码位置,只能让QA去复测,所以对应发布的APK版本,最好有一个Mapping文件备份,方便查找问题。
复现之后拿Log中的hprof文件来分析,当然,Log文件里面生成的并不是hprof文件,需要先经过MAT工具进行转化,扯淡的是官网MAC平台的MAT工具一打开就闪退,让同事在Window上帮忙转化成hprof文件。如果OOM问题较容易复现,可以直接用MAT工具抓取分析。或者直接在工程里面集成LeakCanary工具检测内存泄露的问题代码。
拿到转化后的hprof文件直接拖进AndroidStudio 3.0就可以查看详细信息了。
关于hprof文件的相关信息,可以参考官网:HPROF: A Heap/CPU Profiling Tool
三、OOM实例问题分析定位
点击左侧列表Retained Size进行降序排序,把内存占用大头找出来,Collections只有三个,但是内存占用又那么多,肯定有问题,选中之后看右侧第二个数据明显有异常。
选中右上方问题对象之后,下方展开列出问题对象详细的信息,混淆之后的对象是ade$b。
知道了混淆的对象就可以在混淆Mapping文件中查找相应的问题类对象。
在文件中查找ade$b,知道了相应的混淆类是LoggerThread,接下来在项目工程中查找LoggerThread类。
可以确认问题原因是Log输出太多了,来不及写到文件,导致占用内存到30多兆,实际上很多系统给应用分配的内存也就60MB左右,一个Log输出占了一半内存,出现OOM也就不奇怪了,继续查找到底是哪个对象输出过多。
查看异常对象的详细信息。
继续分析为何会输出过多,是否接口回调次数过多导致。
查看Log输出的逻辑代码调用,异常Log的输出在一个Runnable里面,查看这个Runnable调用的地方,找到以上的调用问题,这傻事估计很多人干过,startTmcThrough()函数在每次接口回调的时候都会调用,在post一个Runnable之前要先把这个Runnable从现有队列里面移除掉,否则每次调用这个函数都往队列里面加了一条Runnable,用户反馈在多次路线偏航之后出现OOM,这个函数是在规划得到新路线的时候调用,多次偏航之后相当于有多个Runnable在消息队列里面持续地输出Log信息,而且这个Log信息内容又偏多,最终导致来不及写入文件出现OOM异常。
四、OOM参考资料
《基于Android Studio的内存泄露检测与解决全攻略》
Android – 彻底消灭OOM的实战经验分享(千分之1.5 -> 万分之0.2)
转载请注明出处:陈文管的博客 – Android OOM问题分析
扫码或搜索:文呓
微信公众号 扫一扫关注