Android 捕获OOM方法

时间:2022-06-26 20:57:39

本文不是讲什么时候会发生OOM,而是讲OOM发生了如何去捕获他,处理它

最近在分析Volley通信框架,看到ImageRequest的一段代码,非常值得借鉴

    /** Decoding lock so that we don't decode more than one image at a time (to avoid OOM's) */
private static final Object sDecodeLock = new Object();
/**
* The real guts of parseNetworkResponse. Broken out for readability.
*/

@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
// Serialize all decode on a global lock to reduce concurrent heap usage.
synchronized (sDecodeLock) {
try {
return doParse(response);
} catch (OutOfMemoryError e) {
VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());
return Response.error(new ParseError(e));
}
}
}
private Response<Bitmap> doParse(NetworkResponse response) {
......
}
  1. 首先使用sDecodeLock同步锁,防止多线程同时解析一张以上图片,可以减少解析图片时发生OOM发生概率
  2. 然后捕获Error,注意不是异常,此时如果捕获Exception是无效的,但是可以捕获Throwable,因为Error和Exception都继承自Throwable OutOfMemoryError -VirtualMachineError -Error -Throwable

程序请求分配的内存超过虚拟机分配的内存,那么就会发生OOM

参考:
JVM—内存溢出、OutOfMemoryError、*Error
摘抄重要的句子
虚拟机栈
栈的作用:栈用于存储局部变量表、操作数栈、动态链接和方法出口等信息.
其中局部变量表用于存放8种基本数据类型(boolean,byte,char,short,int,float,long,double)和reference类型.
reference类型:
- 指向对象起始地址的引用指针
- 指向一个代表对象的句柄
- 指向一条字节码指令的地址

可抛出两种异常状况

  • 线程请求的栈深度大于虚拟机所允许的栈深度,抛出*Error异常
  • 当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常是


堆的作用:分配所有的对象实例和数组。可以抛出OutOfMemoryError异常。

*Error
在单线程的堆中我们不断的让一个成员变量自增,容纳这个变量的单元无法承受这个变量了,就抛出*Error了。
可以开尽量多的线程,并在每个线程里调用native的方法,就自然会抛出 OutOfMemoryError了。

/**
* VM Args: - Xss64k
* @author Administrator
*
*/

public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength ++;
stackLeak();
}
public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeak();
} catch(Throwable e){
System. out.println("Stack length:" + oom.stackLength);
throw e;
}
}
}

现在终于知道了*Error和OutOfMemoryError的区别了