Android 捕獲OOM方法

本文不是講什麼時候會發生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、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的區別了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章