安卓开发中的OOM问题

来源:互联网 发布:罗斯玛丽的婴儿知乎 编辑:程序博客网 时间:2024/04/30 02:50

      OOM - Out of Memory,即为内存溢出;一般是由于程序编写者对内存使用不当,如对该释放的内存资源没有释放,导致其一直不能被再次使用而使计算机内存被耗尽的现象。重启计算机即可,但根本解决办法还是对代码进行优化。

      OOM问题通常出现在用到很多图片或者图片很大的APP开发中(很遗憾笔者目前还没遇到过……因为开发的APP测试数据就几十组,图片也就几十张)。按常理来说,手机系统一般都有足够的内存来提供给APP的这部分图片加载,但是由于系统需要预留内存给其他的应用,因此并不会多分内存,所以就会抛出OOM错误。

 有个问题在于:Android可以GC自动回收资源,那么为什么还会出现OOM?主要原因在于GC会根据特定算法回收程序不用的内存,但GC回收的对象一般是废弃的对象内存或者软引用的引用资源(这也是软引用资源的好处,GC会自动回收,一定几率避免OOM问题)。

 那么既然GC无法解决OOM问题,要通过什么方式来避免OOM?笔者通过收集整理了避免OOM问题的方法,并进行一定尝试,在此做出总结:

 ①对于超大图片,在它加载到内存前,先算出bitmap的大小,通过适当调节采样率使得加载的图片刚刚好;

 ②图像加载问题在listview或者Gallery控件一次加载大量图片时,只加载屏幕能显示范围内的图片(比如需要通过下拉才能看到的图片先不加载),下拉后,之前加载的图片资源及时释放。这里涉及到编程习惯养成的问题,对于不显示时的图片,要直接置NULL或者recycle;对于图像缓存问题,采用软引用缓存到内存,而非每次访问都要重新加载。

 ③改善编码方式:平时编码时要注意采用低内存占用的方式,比如Bitmap.Config.ARGB_4444要比Bitmap.Config.ARGB_8888更省内存

 ④慎用static:用static修饰成员变量时,该变量属于该类,它的生命周期很长,如果用它来引用一些内存占用太多的实例,就很容易导致OOM

 ⑤利用Cache:将Bitmap的内存单独放在Cache中管理,用LinkedHashMap,值的访问会不断往Cache中添加元素;当Cache满了时,再向其中添加一个值,在队列最后的值就会从队列中移除,这个值就可能被GC回收掉,一定程度上避免OOM;

 ⑥三级缓存:这点是结合上面第5点来提的,利用内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference)。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。 

也即是说,用LinkedHashMap类型来进行一级缓存Bitmap的容器。由于LinkeHashMap的特殊性,我们可以控制其内存存储对象的个数并且将不在使用的对象从容器中移除,放到softreference二级缓存里,我们可以在一级缓存中一致保存最近被访问到的bitmap对象,而已经被访问过的图片在LinkedHashMap的容量超过我们预设值时将会把容器中存在的时间最长的对象移除,这个时候我么可以将被移除的LinkedHashMap中的放到二级缓存容器,而二级缓存中的对象管理就交给系统来做了,当系统需要gc时就会首先回收二级缓存容器的Bitmap对象了。

 在获取图片对象时候先从一级缓存容器中查找,如果有对应对象并可用直接返回,如果没有的话从二级缓存中查找对应的SoftReference, 判断SoftReference对象持有的Bitmap是否可用,可用直接返回,否则返回空。如果二级缓存都找不到图片,那就直接从三级缓存即网络中加载图片资源。


  总而言之,关于第二点的图片加载问题的处理方法,即图片不显示时置NULL或recycle,如果能够保持这个良好的编程习惯,基本很少会出现OOM。其他的方法也是在程序开发时需要注意的问题,只要做适当的处理,或许你很难再见到Out of memory  or  java.lang.OutOfMemoryError.

0 0
原创粉丝点击