Android 内存溢出(OOM)问题分析方法

时间:2022-04-27 16:21:59
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,它会在处理完交代给它的任务之后尽快结束自己。