内存溢出的主要导致原因有如下几类:
-
应用代码存在内存泄露,长时间积累无法释放导致OOM;
-
应用的某些逻辑操作疯狂的消耗掉大量内存(譬如加载一张不经过处理的超大超高清图片等)导致超过阈值OOM;
可以发现,无论哪种类型,导致内存溢出(OutOfMemoryError)的核心原因就是应用的内存超过阈值了。
我们有时也遇到,第一反应是去分析OOM异常打印栈,可是后来发现打印栈打印的地方没有啥问题,没有可优化的余地了,于是就郁闷了。其实这时候你留心观察几个现象即可,如下:
- 留意你执行触发OOM操作前的界面是否有卡顿或者比较密集的GC打印;
- 使用命令查看下当前应用占用内存情况;
确认了以上这些现象你基本可以断定该OOM的log真的没用,真正导致问题的原因是内存泄露,所以我们应该按照上节介绍的方式去着手排查内存泄露问题,解决掉内存泄露后红色空间都能得到释放,再去显示一张0.8M的优化图片就不会再报OOM异常了。
如下给出一些我们应用开发中的常用的策略建议:
-
时刻记得不要加载过大的Bitmap对象;譬如对于类似图片加载我们要通过BitmapFactory.Options设置图片的一些采样比率和复用等,具体做法点我参考官方文档,不过过我们一般都用fresco或Glide开源库进行加载。
-
优化界面交互过程中频繁的内存使用;譬如在列表等操作中只加载可见区域的Bitmap、滑动时不加载、停止滑动后再开始加载。
-
有些地方避免使用强引用,替换为弱引用等操作。
-
避免各种内存泄露的存在导致OOM。
-
对批量加载等操作进行缓存设计,譬如列表图片显示,Adapter的convertView缓存等。
-
尽可能的复用资源;譬如系统本身有很多字符串、颜色、图片、动画、样式以及简单布局等资源可供我们直接使用,我们自己也要尽量复用style等资源达到节约内存。
-
对于有缓存等存在的应用尽量实现onLowMemory()和onTrimMemory()方法。
-
尽量使用线程池替代多线程操作,这样可以节约内存及CPU占用率。
-
尽量管理好自己的Service、Thread等后台的生命周期,不要浪费内存占用。
-
尽可能的不要使用依赖注入,中看不中用。
-
尽量在做一些大内存分配等可疑内存操作时进行try catch操作,避免不必要的应用闪退。
-
尽量的优化自己的代码,减少冗余,进行编译打包等优化对齐处理,避免类加载时浪费内存。
可以发现,上面只是列出了我们开发中常见的导致OOM异常的一些规避原则,还有很多相信还没有列出来,大家可以自行追加参考即可。