Android 关于OOM的解决方案

在Android平台上面,应用程序OOM异常永远都是值得关注的问题。通常这一块也是程序这中的重点之一。这下我就如何解决OOM,提供几个方法.

首先要了解什么是OOM?

OOM就是内存溢出,即Out Of Memory。Android设备内存一般比较小,每个应用程序在专有的Dalvik虚拟机实例中运行,也就是说内存占有量超过了VM所分配的最大值。

具体原因:

1、一个进程的内存可以由2个部门组成:java 使用内存 ,C 使用内存 ,这两个内存的和必需小于16M,不然就会出现各人熟悉的OOM。

2、一旦内存分配给Java后,以后这块内存纵然开释后,也只能给Java的使用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关,反正C就别想用到这块的内存了,所以要是Java突然占用了一个大块内存,纵然很快开释了,C能使用的内存 = 16M - Java某一瞬间占在的最大内存。 

3、而Bitmap的生成是路程经过过程malloc进行内存分配的,占用的是C的内存。

根据这个原理那么我们就可以有效的避免OOM的出现,具体我们可以做以下一些额外的工作来有效避免OOM

一丶设计Cache

这种方式,我觉得是比较好的一种,它首先利用了cache,我认为cache是一个很重要的东西,把Bitmap的内存单独放在一个地方来管理,这个地方就是cache,它的容量是一定的,我们可能会不断的向这个cache中添加元素,也可能不断的移除元素。

为了更好的说明这种方式,先要介绍一下LruCache算法。

 1、这其实就是一个LinkedHashMap,任意时刻,当一个值被访问时,它就会被移动到队列的开始位置,所以这也是为什么要用LinkedHashMap的原因,因为要频繁的做移动操作,为了提高性能,所以要用LinkedHashMap。当cache满了时,此时再向cache里面添加一个值,那么,在队列最后的值就会从队列里面移除,这个值就有可能被GC回收掉。

   2、如果我们想主动释放内存,也是可以的,我们可以重写entryRemoved(Boolean, K, V, V)方法。

3、
<span style="font-family:KaiTi_GB2312;">synchronized (cache) {
     if (cache.get(key) == null) {
         cache.put(key, value);
   }}</span>
4、 LruCache的APILevel是12,也就是说,我们在SDK 2.3.x以下是无法使用的,但是没关系,LruCache的源码不算复杂,我们可以直接把它拷贝到自己的工程目录就可以了

 AsyncTask<>

    这个类也是一个很重要也很常用的类。它封装了Thread和Handler,我们使用就更加方便,不用关注Handler,我们知道,在后台线程中是不能更新UI,而很多情况下,我们在后台线程做完一件事情后,一般都会更新UI,一般的做法是向关联到UI线程的Handler发送一个message,在Handler里面去处理这个message,从而更新UI。用了AsyncTask之后,我们就不用关注Handler了。这个类有几个重要的方法:

    1、onPreExecute(): 在UI线程里面调用,它在这个task执行后会立即调用。我们在这个方法里面通常是用于建立一个任务,比如显示一个等待对话框来通知用户。

    2、doInBackground(Params...):这个方法从名字就可以看出,它是运行在后台线程的,在这个方法里面,去做耗时的事情,比如下载访问网络,操作文件等。这这个方法里面,我们可以调用publishProgress(Progress...)来调用当前任务的进度,调用了这个方法后,对应的onProgressUpdate(Progress...)方法会被调用,这个方法是运行在UI线程的。

    3、onProgressUpdate(Progress...):运行在UI线程,在调用publishProgress()方法之后。这个方法用来在UI上显示任何形式的进度,比如你可以显示一个等待对话框,也可以显示一个文本形式的log,还可以显示toast对话框。

    4、onPostExecute(Result):当task结束后调用,它运行在UI线程。

    5、取消一个task,我们可以在任何时候调用cancel(Boolean)来取消一个任务,当调用了cancel()方法后,onCancelled(Object)方法就会被调用,onPostExecute(Object)方法不会被调用,在doInBackground(Object[])方法中,我们可以用isCancelled()方法来检查任务是否取消。

    6、几点规则

  • AsyncTask实例必须在UI线程中创建   
  • execute(Params...)方法必须在UI线程中调用。
  • 不用手动调用onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate()方法。
  • 一个任务只能被执行一次。
二、内存泄漏导致内存溢出

1、资源释放问题。如长期保持某些资源的引用。如Context,Cursor,Io流的引用,资源得不到释放造成内存泄漏。所以,使用数据库,Io流的时候记得关闭资源。同时设置成null,不要老是指望垃圾回收器为你工作。如果不设置成null,那么资源回收会受到一定的影响。

2、对象内存过大。保存了多个耗用内存过大的对象,如Bitmap、XML文件,造成内存超出限制。
3、static关键字的使用。static它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例,就会抛出OOM异常,尽量减少static关键字的使用。因为static的方法或成员被外部使用的话,而外部的牵引对象没有对其进行释放的话那么整个static的类都不会被释放,也就造成内存泄漏。
4、横竖屏切换导致OOM,横竖屏切换会重新调用Activity的生命周期,可能存在XML文件重复加载的问题,可以把XML文件转换成View,再放到一个容器里,然后直接调用setContentView方法,避免XML文件重复加载。
5、构造Adapter时,没有使用ConvertView,我们应该尽量使用ConvertView和viewHolder进行ListView的优化。

6、对于不再使用的bitmap应该手动调用recycle方法,并且设置成null。图片还要尽量使用软引用方式,这样可以加快垃圾回收。

三、总结
总的来说在代码实现的过程中,每个环节都有可能是导致OOM的罪魁祸首,只是在图片解码的过程中体现出来了而已。所以在整个编码过程中应该采用一些比较好的编码方式,有时需要对程序进行多次优化来减少内存开销。Java的垃圾回收机制某种程度上给我们带了方便,但是在嵌入式方面还有一些不足,毕竟嵌入式的资源是非常珍贵的,一旦控制不好就会出现OOM。做代码优化之前我们也需要深入理解垃圾回收机制,这样才能有效的控制内存消耗。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值