天天看點

android 加載圖檔oom若幹方案小結

本文根據網上提供的一些技術方案加上自己實際開發中遇到的情況小結。

衆所周知,每個android應用程式在運作時都有一定的記憶體限制,限制大小一般為16mb或24mb(視手機而定)。一般我們可以通過擷取目前線程的可運作記憶體來判斷,比如系統分給目前運作記憶體隻有16m,而你的圖檔就有16m,這肯定會oom的。

相關知識介紹

1.顔色模型

常見的顔色模型有rgb、yuv、cmyk等,在大多數圖像api中采用的都是rgb模型,android也是如此;另外,在android中還有包含透明度alpha的顔色模型,即argb。

2.計算機中顔色值的數字化編碼

(1)浮點數編碼:比如float: (1.0, 0.5, 0.75),每個顔色分量各占1個float字段,其中1.0表示該分量的值為全紅或全綠或全藍;

(2)24位的整數編碼:比如24-bit:(255, 128, 196),每個顔色分量各占8位,取值範圍0-255,其中255表示該分量的值為全紅或全綠或全藍;

(3)16位的整數編碼:比如16-bit:(31, 45, 31),第1和第3個顔色分量各占5位,取值範圍0-31,第2個顔色分量占6位,取值範圍0-63;

3.bitmap在記憶體中的存儲區域

http://www.7dot9.com/2010/08/android-bitmap%e5%86%85%e5%ad%98%e9%99%90%e5%88%b6/一文中對android記憶體限制問題做了一些探讨,作者認為bitmap對象通過棧上的引用來指向堆上的bitmap對象,而bitmap對象又對應了一個使用了外部存儲的native圖像,實際上使用的是byte[]來存儲的記憶體空間。但為了確定外部配置設定記憶體成功,應該保證目前已配置設定的記憶體加上目前需要配置設定的記憶體值,大小不能超過目前堆的最大記憶體值,而且記憶體管理上将外部記憶體完全當成了目前堆的一部分。

4.java對象的引用類型

(1)強引用(strongreference)如果一個對象具有強引用,那垃圾回收器絕不會回收它。當記憶體空間不足,java虛拟機甯願抛出outofmemoryerror錯誤,使程式異常終止,也不會靠随意回收具有強引用的對象來解決記憶體不足的問題。

(2)軟引用(softreference)如果一個對象隻具有軟引用,則記憶體空間足夠,垃圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體。隻要垃圾回收器沒有回收它,該對象就可以被程式使用。

(3)弱引用(weakreference)弱引用與軟引用的差別在于:隻具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的記憶體區域的過程中,一旦發現了隻具有弱引用的對象,不管目前記憶體空間足夠與否,都會回收它的記憶體。

(4)虛引用(phantomreference)“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

有了上面的基礎儲備,我們來談談圖檔的oom解決方案:

(1)緩存圖像到記憶體,采用軟引用緩存到記憶體,而不是在每次使用的時候都從新加載到記憶體;

(2)調整圖像大小,手機螢幕尺寸有限,配置設定給圖像的顯示區域本身就更小,有時圖像大小可以做适當調整;

(3)采用低記憶體占用量的編碼方式,比如bitmap.config.argb_4444比bitmap.config.argb_8888更省記憶體;

(4)及時回收圖像,如果引用了大量bitmap對象,而應用又不需要同時顯示所有圖檔,可以将暫時用不到的bitmap對象及時回收掉;

(5)自定義堆記憶體配置設定大小,優化dalvik虛拟機的堆記憶體配置設定;(這裡可以參照一些第三方的圖檔緩存架構)

場景示範

為了說明出現oom的場景和解決oom的方法,我們選取了兩款不同的機型來做比較:

(1)該應用展示一個gallery,該gallery隻加載圖檔,gallery的adapter中傳入圖檔的路徑而不是圖檔對象本身,adapter動态加載圖檔;

(2)示範所用的圖檔預存儲到sdcard的cache目錄下,檔案名分别為a.jpg,b.jpg…r.jpg,總共18張;

(3)圖檔為規格1920*1200的jpg圖檔,檔案大小在423kb-1.48mb範圍内;

(4)運作環境:模拟器——android2.2版本系統——480*320螢幕尺寸;moto defy——2.3.4版本cm7系統——854*480螢幕尺寸;

1.示範一

首先采用最簡單的圖檔加載方式,不帶任何圖檔緩存、調整大小或者回收,simpleimageloader.class便是承擔此職責。加載圖檔部分的代碼如下:

@override public bitmap loadbitmapimage(string path) { return bitmapfactory.decodefile(path); } public drawable loaddrawableimage(string path) { return new bitmapdrawable(path);

示範結果:在模拟器上圖檔隻能加載1-3張,之後便會出現oom錯誤;在defy上不會出現錯誤;原因是兩者記憶體限制不同,defy上運作的是第三方rom,記憶體配置設定有40mb。另外gallery每次顯示一張圖檔時,都要重新解析獲得一張圖檔,盡管在defy上還未曾出錯,但當圖檔量加大,gc回收不及時時,還是有可能出現oom。

2.示範二

為圖檔加載的添加一個軟引用緩存,每次圖檔從緩存中擷取圖檔對象,若緩存中不存在,才會從sdcard加載圖檔,并将該對象加入緩存。同時軟引用的對象也有助于gc在記憶體不足的時候回收它們。常見的discache就是這個原理,大家有興趣的可以自行研究。關鍵代碼

private hashmap> mimagecache; if(mimagecache.containskey(path)) { softreferencesoftreference = mimagecache.get(path); bitmap bitmap = softreference.get(); if(null != bitmap) return bitmap; bitmap bitmap = bitmapfactory.decodefile(path); mimagecache.put(path, new softreference(bitmap)); return new bitmapdrawable(loadbitmapimage(path));

3.示範三

為了進一步避免oom,除了緩存,還可以對圖檔進行壓縮,進一步節省記憶體,多數情況下調整圖檔大小并不會影響應用的表現力。這個也是我之前必定做的,就是對圖檔進行壓縮。

bitmapfactory.options options = new bitmapfactory.options(); options.injustdecodebounds = true;//如果該 值設為true那麼将不傳回實際的bitmap,也不給其配置設定記憶體空間,這樣就避免記憶體溢出. bitmapfactory.decodefile(path, options);

可以對圖檔按尺寸壓縮,也是不錯的方案:

options.insamplesize = util.computesamplesize(options, 600, (int) (1 * 1024 * 1024)); options.injustdecodebounds = false; options.indither = false; options.inpreferredconfig = bitmap.config.argb_8888; bitmap bitmap = bitmapfactory.decodefile(path, options);

4.示範四

在有些情況下,嚴重縮小圖檔還是會影響應用的顯示效果的,是以有必要在盡可能少地縮小圖檔的前提下展示圖檔,手動去回收圖檔就變得尤為重要。是以這也是一些第三方圖檔庫管理的時候必定用到lrucache算法的原因。

<a target="_blank" href="http://blog.csdn.net/guolin_blog/article/details/34093441">blog.csdn.net/guolin_blog/article/details/34093441</a>

_blog/article/details/34093441

上一篇: 工廠模式
下一篇: 網易面試

繼續閱讀