在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,那么资源回收会受到一定的影响。
6、对于不再使用的bitmap应该手动调用recycle方法,并且设置成null。图片还要尽量使用软引用方式,这样可以加快垃圾回收。