零零碎碎的东西总是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无意中发现了这个每日一道面试题,想了想如果只是简单地去思考,那么不仅会收效甚微,甚至难一点的题目自己可能都懒得去想,坚持不下来。所以不如把每一次的思考、理解以及别人的见解记录下来。不仅加深自己的理解,更要激励自己坚持下去。
什么是OOM
“OOM”也就是“out of memory”,意思是内存用完了。也就是说,当你去申请内存的时候,你需要的内存过大,app剩下的空余内存已经不够你使用,如果你没有捕获这个异常,系统就没办法了,会直接崩溃并抛出OOM异常。
系统分配给每一个app运行的内存空间是有限的,所以作为一名Android开发者,我们一定要谨慎小心的使用内存。
OOM的类型
首先OOM的原因就是app进程可用内存不足,有两种情况
- 内存申请的速度大于gc释放内存的速度
- 内存出现泄漏,gc无法回收泄露的内存,导致可用内存越来越少
第一种情况又会有两种不同的类型
- 一次性需要的内存过大,可用内存不足。常见的是使用图片资源时加载为bitmap存储到内存,图片分辨率越高,需要的内存就越大,就可能造成OOM。
- 频繁的创建内存占用小的对象,导致内存碎片,这种叫内存抖动。虽然整体上还有内存可分配,但是这些内存空间并不连续,无法满足需求,导致OOM。常见的有ListView中contentView的创建、频繁使用String进行字符串的拼接、onDraw方法里对象的频繁创建。这一类问题要解决基本的方法就是复用已创建的对象
第二种情况就是内存泄漏,内存泄漏与OOM的关系就是量变到质变的过程,内存泄漏必定会导致可用内存的减少,大量的内存泄漏就会导致OOM问题。关于内存泄漏的具体例子在第3期已经很详细的探讨过,这里就不再赘述。
OOM的预防
这里总结几点,无非是两个方面:
- 提高系统分配的可用内存。假如app确实需要很大的内存空间,那么可以再manifest文件中设置
largeHeap="true"
增加内存的的申请量 - 减少app的内存使用
- ImageView使用合适的尺寸,多图显示缩略图,点击查看大图
- ListView使用ViewHolder复用contentView。不过现在大都用RecycleView,强制配合ViewHolder使用
- 减少bitmap对象内存的占用,可用Lru缓存、三级缓存、合适的编码等
- onDraw等频繁调用的方法中避免创建对象
- 优化布局,少用LinerLayout多用RelativeLayout
- 字符串拼接问题尽量使用StringBuilder而不是String的+
在内存泄漏方面
- 使用静态内部类
- 静态类引用使用Application的Context而不是Activity的Context
- 类似广播、监听器等记得取消注册
- 游标、文件等资源使用完毕一定要关闭
- 静态集合使用完毕记得清空
- 根据不同场景,善用软引用、弱引用