本文不是講什麼時候會發生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) {
......
}
- 首先使用sDecodeLock同步鎖,防止多線程同時解析一張以上圖片,可以減少解析圖片時發生OOM發生概率
- 然後捕獲Error,注意不是異常,此時如果捕獲Exception是無效的,但是可以捕獲Throwable,因爲Error和Exception都繼承自Throwable OutOfMemoryError -VirtualMachineError -Error -Throwable
程序請求分配的內存超過虛擬機分配的內存,那麼就會發生OOM
參考:
JVM—內存溢出、OutOfMemoryError、StackOverflowError
摘抄重要的句子
虛擬機棧
棧的作用:棧用於存儲局部變量表、操作數棧、動態鏈接和方法出口等信息.
其中局部變量表用於存放8種基本數據類型(boolean,byte,char,short,int,float,long,double)和reference類型.
reference類型:
- 指向對象起始地址的引用指針
- 指向一個代表對象的句柄
- 指向一條字節碼指令的地址
可拋出兩種異常狀況
- 線程請求的棧深度大於虛擬機所允許的棧深度,拋出StackOverflowError異常
- 當擴展時無法申請到足夠的內存時會拋出OutOfMemoryError異常是
堆
堆的作用:分配所有的對象實例和數組。可以拋出OutOfMemoryError異常。
StackOverflowError
在單線程的堆中我們不斷的讓一個成員變量自增,容納這個變量的單元無法承受這個變量了,就拋出StackOverflowError了。
可以開儘量多的線程,並在每個線程裏調用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;
}
}
}
現在終於知道了StackOverflowError和OutOfMemoryError的區別了