Android載入圖片導致記憶體溢出(Out of Memory異常)

來源:互聯網
上載者:User

標籤:

Android在載入大背景圖或者大量圖片時,經常導致記憶體溢出(Out of Memory Error),本文根據我處理這些問題的經曆及其它開發人員的經驗,整理解決方案如下(部分代碼及文字出處無法考證):


方案一、讀取圖片時注意方法的調用,適當壓縮盡量不要使用 setImageBitmapsetImageResourceBitmapFactory.decodeResource來設定一張大圖,因為這些函數在完成decode後,最終都是通過java層的 createBitmap來完成的,需要消耗更多記憶體。因此,改用先通過 BitmapFactory.decodeStream方法,建立出一個bitmap,再將其設為ImageView的 source, decodeStream最大的秘密在於其直接調用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。

        InputStream is = this.getResources().openRawResource(R.drawable.pic1);

        BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = false;

        options.inSampleSize = 10;   // width,hight設為原來的十分一

        Bitmap btp = BitmapFactory.decodeStream(is, null, options);

 如果在讀取時加片的Config參數,可以跟有效減少載入的記憶體,從而跟有效阻止拋out of Memory異常。

  /**

     * 以最省記憶體的方式讀取本地資源的圖片

     * @param context

     * @param resId

     * @return

     */

    public static Bitmap readBitMap(Context context, int resId){ 

        BitmapFactory.Options opt = new BitmapFactory.Options();

        opt.inPreferredConfig = Bitmap.Config.RGB_565;

        opt.inPurgeable = true;

        opt.inInputShareable = true;

        // 擷取資源圖片

        InputStream is = context.getResources().openRawResource(resId);

        return BitmapFactory.decodeStream(is, null, opt);

        }

 另外,decodeStream直接拿圖片來讀取位元組碼, 不會根據機器的各種解析度來自動適應,使用了decodeStream之後,需要在hdpi和mdpi,ldpi中配置相應的圖片資源, 否則在不同解析度機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。  方案二、在適當的時候及時回收圖片佔用的記憶體通常Activity或者Fragment在onStop/onDestroy時候就可以釋放圖片資源:

 if(imageView != null && imageView.getDrawable() != null){     

      Bitmap oldBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();    

      imageView.setImageDrawable(null);    

      if(oldBitmap != null){    

            oldBitmap.recycle();    

            oldBitmap = null;   

      }    

 }   

 // Other code.

 System.gc();

 

 在釋放資源時,需要注意釋放的Bitmap或者相關的Drawable是否有被其它類引用。如果正常的調用,可以通過 Bitmap.isRecycled()方法來判斷是否有被標記回收;而如果是被UI線程的介面相關代碼使用,就需要特別小心避免回收有可能被使用的資源,不然有可能拋出系統異常:E/AndroidRuntime: java.lang.IllegalArgumentException: Cannot draw recycled bitmaps並且該異常無法有效捕捉並處理。  方案三、不必要的時候避免圖片的完整載入只需要知道圖片大小的情形下,可以不完整載入圖片到記憶體。在使用 BitmapFactory壓縮圖片的時候, BitmapFactory.Options設定 inJustDecodeBounds為true後,再使用 decodeFile()等方法,可以在不分配空間狀態下計算出圖片的大小。樣本: 

 BitmapFactory.Options opts = new BitmapFactory.Options();    

 // 設定inJustDecodeBounds為true    

 opts.inJustDecodeBounds = true;    

 // 使用decodeFile方法得到圖片的寬和高    

 BitmapFactory.decodeFile(path, opts);    

 // 列印出圖片的寬和高

 Log.d("example", opts.outWidth + "," + opts.outHeight);

(ps:原理其實就是通過圖片的頭部資訊讀取圖片的基本資料)  方案四、最佳化Dalvik虛擬機器的堆記憶體配置堆(HEAP)是VM中佔用記憶體最多的部分,通常是動態分配的。堆的大小不是一成不變的,通常有一個分配機制來控制它的大小。比如初始的HEAP是4M大,當4M的空間被佔用超過75%的時候,重新分配堆為8M大;當8M被佔用超過75%,分配堆為16M大。倒過來,當16M的堆利用不足30%的時候,縮減它的大小為8M大。重新設定堆的大小,尤其是壓縮,一般會涉及到記憶體的拷貝,所以變更堆的大小對效率有不良影響。Heap Utilization是堆的利用率。當實際的利用率偏離這個百分比的時候,虛擬機器會在GC的時候調整堆記憶體大小,讓實際佔用率向個百分比靠攏。使用  dalvik.system.VMRuntime類提供的 setTargetHeapUtilization方法可以增強程式堆記憶體的處理效率。

 private final static float TARGET_HEAP_UTILIZATION = 0.75f;    

 // 在程式onCreate時就可以調用

 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

  方案五、自訂堆(Heap)記憶體大小對於一些Android項目,影響效能瓶頸的主要是Android自己記憶體管理機制問題,目前手機廠商對RAM都比較吝嗇,對於軟體的流暢性來說RAM對效能的影響十分敏感,除了最佳化Dalvik虛擬機器的堆記憶體配置外,我們還可以強制定義自己軟體的對記憶體大小,我們使用Dalvik提供的 dalvik.system.VMRuntime類來設定最小堆記憶體為例:

 private final static int CWJ_HEAP_SIZE = 6 * 1024 * 1024 ;

 VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); // 設定最小heap記憶體為6MB大小。

 但是上面方法還是存在問題,函數 setMinimumHeapSize其實只是改變了堆的下限值,它可以防止過於頻繁的堆記憶體配置,當設定最小堆記憶體大小超過上限值(Max Heap Size)時仍然採用堆的上限值,對於記憶體不足沒什麼作用。 最後介紹一片佔用進程的記憶體演算法。android中處理圖片的基礎類是Bitmap,顧名思義,就是位元影像。佔用記憶體的演算法如:圖片的width*height*Config。如果Config設定為ARGB_8888,那麼上面的Config就是4。一張480*320的圖片佔用的記憶體就是480*320*4 byte。在預設情況下android進程的記憶體佔用量為16M,因為Bitmap他除了java中持有資料外,底層C++的 skia圖形庫還會持有一個SKBitmap對象,因此一般圖片佔用記憶體推薦大小應該不超過8M。這個可以調整,編譯原始碼時可以設定參數。 轉:http://zwkufo.blog.163.com/blog/static/2588251201312864034812/ 】

Android載入圖片導致記憶體溢出(Out of Memory異常)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.