Android 内存溢出(OOM)问题分析方法
oom的原因?
1)对象设计不合理(单个对象的内存占用过大、同类对象未重复利用);
2)一次性申请很大内存导致超出了系统对单个应用设定的内存上限(Dalvik Heap Size);
3)内存泄漏
如何利用工具定位oom?
1) 先查找发生oom的是哪个activity?
可采取的查找方式有:对每个activity使用adb shell dumpsys meminfo "process name",查看哪个activity未被释放;借助heap viewer,手动GC,看哪个activiy的allocated size持续增长;
2) 打开Android Monitor,操作1)中所定位的activity(多次打开-关闭),生成hprof文件。hprof文件需要用sdk/platform-tools中的hprof-conv转化后(终端输命令提示hprof-conv“未找到命令”,可尝试输入hprof-conv的完整绝对路径)再用MAT打开,分析是哪个对象导致activity无法被释放。
如何避免oom?
减小对象的内存占用
1)使用轻量级的数据结构,例如尽量使用常量代替枚举类型(枚举类型是常量内存的2倍左右);
2)bitmap在decode时选择合适的inSampleSize进行缩小;
3)xml尽量使用更小的图片,否则有可能初始化时因内存不足引起InflationException;
内存对象的重复利用
1)ListView/GridView的getView中加入ConvertView的复用
2)Bitmap对象的复用(3级缓存),避免重复申请对象
3)类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。
4)对于大量的字符串拼接的操作,使用StringBuilder来替代频繁的“+”。
避免对象的内存泄露
1)内部类引用导致的泄漏(典型场景activity中Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏)
2)Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏
3)监听器和observer的注销
4)Cursor对象是否及时关闭
内存使用策略优化
1)考虑使用Application Context而不是Activity Context
2)资源文件需要选择合适的文件夹进行存放(例如xxhdpi的手机去引用hdpi目录下的图片会将其拉伸而显著提高内存占用)
3)Try catch某些大内存分配的操作(decode bitmap的时候,catch到OOM,可以尝试把采样比例再增加一倍之后,再次尝试decode)
4)谨慎使用static对象,因其生命周期和整个应用进程一致
5)珍惜Services资源,后台service在任务执行完毕后要及时停止,否则系统会倾向为了保留这个Service而一直保留Service所在的进程,导致该进程不能被回收。建议使用IntentService,它会在处理完交代给它的任务之后尽快结束自己。