一、前期基础知识储备
(1)OOM定义—out of memory,内存溢出,一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它垃圾回收器就无法回收它,当该对象占用的内存无法被回收时,就容易造成内存泄露。多个内存泄漏最终会导致内存溢出,即OOM。
(内存泄漏和内存溢出两者之间的关系,可参考笔者之前的文章《Android中内存泄漏详解》)
(2)Java内存概念、内存泄漏相关知识点都可以参考笔者的文章《Android中内存泄漏详解》
二、出现OOM错误的常见原因
(1)资源对象没关闭造成的内存泄露,try catch finally中将资源回收放到finally语句可以有效避免OOM。资源性对象比如:
①Cursor游标对象没有关闭;
②调用registerReceiver后未调用unregisterReceiver();
③未关闭InputStream/OutputStream;
④Bitmap使用后未调用recycle()
(2)作用域不一样,导致对象不能被垃圾回收器回收,比如:
①非静态内部类会隐式地持有外部类的引用,
②Context泄露——概括一下,避免Context相关的内存泄露,记住以下事情:
- 不要保留对Context-Activity长时间的引用(对Activity的引用的时候,必须确保拥有和Activity一样的生命周期)
- 尝试使用Context-Application来替代Context-Activity
- 如果你不想控制内部类的生命周期,应避免在Activity中使用非静态的内部类,而应该使用静态的内部类,并在其中创建一个对Activity的弱引用。
③Thread 引用其他对象也容易出现对象泄露。
④onReceive方法里执行了太多的操作
(3)内存压力过大—最直接:
①图片资源加载过多,超过内存使用空间,例如Bitmap 的使用,bitmap分辨率越高,所占用的内存就越大,这个是以2为指数级增长的;
②重复创建view,listview应该使用convertview和viewholder,ListView相关的知识点有两个:1)ListView的实现;2)ListView的效率优化,其中第二点对于开发者在使用ListView时是需要重点关注的,《第一行代码》中有相关介绍。
三、避免OOM的常用方法总结
1)资源文件需要选择合适的文件夹进行存放;
2)优化布局层次,越扁平化的视图布局,占用的内存就越少,效率越高;
3)减小Bitmap对象的内存占用;
4)使用更小的图片,是否存在可以压缩的空间,是否可以使用一张更小的图片;
5)复用系统自带的资源,比如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用;
6)注意在ListView/GridView等出现大量重复子组件的视图里面对ConvertView的复用;
7)类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动;
8)在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”;
9)考虑使用Application Context而不是Activity Context
总结:开发者做好内存优化,就像工程师处理好马达噪音问题一样,是一项长期的工作,需要注意的地方有很多,了解常用的,后期项目中碰到的也要自己总结好。