天天看點

android 減少圖檔出現oom錯誤

在做android圖檔程式的時候,由于圖檔比較多,很有很的機會出現oom的機會,根據網上的資料做了些總結,期待能夠減少oom出現的機會。 1.使用底層的方法來替代使用java層的方法

         盡量不要使用setimagebitmap或setimageresource或bitmapfactory.decoderesource來設定一張大圖。 

 因為這些函數在完成decode後,最終都是通過java層的createbitmap來完成的,需要消耗更多記憶體。 是以,改用先通過bitmapfactory.decodestream方法,建立出一個bitmap,再将其設為imageview的 source, 

decodestream最大的秘密在于其直接調用jni>>nativedecodeasset()來完成decode, 無需再使用java層的createbitmap,進而節省了java層的空間。 

 在讀取時加上圖檔的config參數,可以跟有效減少加載的記憶體,

 通過使用這樣的辦法,能更有效阻止抛out of memory異常 另外,decodestream直接拿的圖檔來讀取位元組碼了, 不會根據機器的各種分辨率來自動适應, 使用了decodestream之後,需要在hdpi和mdpi,ldpi中配置相應的圖檔資源, 否則在不同分辨率機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。 另外,以下方式也大有幫助:

片段一: 

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);   

片段二:

if(!bmp.isrecycle() ){   

         bmp.recycle()   //回收圖檔所占的記憶體   

         system.gc()  //提醒系統及時回收   

}   

片段三:

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);    

  }   

2. 優化虛拟機的堆記憶體使用

對于android平台來說,其托管層使用的dalvik java vm從目前的表現來看還有很多地方可以優化處理,比如我們在開發一些大型遊戲或耗資源的應用中可能考慮手動幹涉gc處理,使用 dalvik.system.vmruntime類提供的settargetheaputilization方法可以增強程式堆記憶體的處理效率。當然具體原理我們可以參考開源工程,這裡我們僅說下使用方法:

  private final static float target_heap_utilization = 0.75f; 

在程式oncreate時就可以調用 vmruntime.getruntime().settargetheaputilization(target_heap_utilization); 即可。 

android堆記憶體也可自己定義大小 

對于一些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大小。

當然對于記憶體吃緊來說還可以通過手動幹涉gc去處理 

    3.其他一些使用技巧

       1.不同大小的圖檔需要做成同一個高度的的縮略圖(如100px),而且要保證圖檔不失真,那怎麼辦?我們總不能将原始圖檔加載到記憶體中再進行縮放處理吧,要知道在移動開發中,記憶體是相當寶貴的,而且一張100k的圖檔,加載完所占用的記憶體何止100k?

   經過研究,發現,options中有個屬性injustdecodebounds,研究了一下,終于明白是什麼意思了,sdk中的e文是這麼說的

      if set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

  意思就是說如果該值設為true那麼将不傳回實際的bitmap不給其配置設定記憶體空間而裡面隻包括一些解碼邊界資訊即圖檔大小資訊,那麼相應的方法也就出來了,通過設定injustdecodebounds為true,擷取到outheight(圖檔原始高度)和 outwidth(圖檔的原始寬度),然後計算一個insamplesize(縮放值),然後就可以取圖檔了,這裡要注意的是,insamplesize 可能小于0,必須做判斷。

            2.用bitmapfactory解碼一張圖檔時,有時會遇到該錯誤。這往往是由于圖檔過大造成的。要想正常使用,則需要配置設定更少的記憶體空間來存儲。

bitmapfactory.options.insamplesize.設定恰當的insamplesize可以使bitmapfactory配置設定更少的空間以消除該錯誤。insamplesize的具體含義請參考sdk文檔。例如:

bitmapfactory.options opts = new bitmapfactory.options();   

opts.insamplesize = 4;  

bitmap bitmap = bitmapfactory.decodefile(imagefile, opts);   

設定恰當的insamplesize是解決該問題的關鍵之一。

繼續閱讀