2012-04-22 29 views
1

我有一個應用程序,它獲取線程中的位圖,然後將位圖放入全局內存緩存中。在一個2.2模擬器,我得到一個可再現了內存不足的錯誤裝載足夠的位圖後,(他們是在一個列表視圖):找出位圖分配在哪裏?

FATAL EXCEPTION: pool-1-thread-1 
    java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
    ... 

堆看起來穩定(3.3MB),如果我能我不知道看不到內存的增長,因爲我認爲在2.2 os中,位圖內存是分開存儲的?我一直在做hprof轉儲並在MAT中查看它們,並且我的對象計數看起來和預期的一樣。

在ICS手機上運行該應用程序不會出現同樣的問題(但也許只是有更多的內存等)。我認爲在後來的操作系統中,他們將位圖內存作爲堆的一部分?

在這兩種情況下,有沒有辦法查看哪些位圖實例已被我的應用程序分配? hprof轉儲只顯示我認爲系統範圍內的總計數。但我看不到他們從哪裏分配。

我使用:

android.support.v4.util.LruCache<String, Bitmap> 

的內存緩存 - 它似乎像位圖數據沒有被清理入口得到驅逐後(我設置緩存有一個5MB的上限)。我記得像recycle()這樣的Bitmap方法,也許它們沒有正確清理?

感謝

回答

1

堆看起來穩定(3.3MB),我不知道如果我不能看到內存量增長 ,因爲我想在2.2的操作系統,內存位分別存儲 ?我一直在做hprof轉儲並在MAT, 中查看它們,並且我的對象計數看起來和預期的一樣。

更正,對於2.x,您無法看到位圖與MAT共同使用的內存(您可以從ICS設備轉儲,並突然看到巨大的跳躍)。但是,可用內存的數量是相同的(不同設備之間的差異,一般在16 MB到32 MB之間)。解決方案是儘可能少地在內存中存儲位圖。如果他們只是縮略圖大小,你可能會忘記將它們留在記憶中,但通常你不能加載那麼多。

1

你是對的更高版本將位圖數據保留在本地堆中。但即便如此,這些數據仍然與位圖預算相符。爲避免此錯誤,您必須致電回收站!因此,擴展LruCache,覆蓋entryRemoved並在那裏調用回收。 此外,我會根據設備內存對緩存進行限制。例如,你可以使用ActivityManager.getMemoryClass()

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 
    int memoryClass = activityManager.getMemoryClass(); 

memoryClass包含以MB爲單位的Dalvik的堆。例如,您可以使用該值的1/5作爲高速緩存的限制。

仍然這可能不足以避免OOM錯誤,因爲位圖內存僅在終結器中釋放。請務必閱讀有關位圖處理的official doc。如果所有失敗,你仍然可以嘗試撥打電話System.gc()entryRemoved,看看是否有幫助。但正如Ewoks指出的那樣,這不僅是不好的做法,而且可能會導致UI-Thread停一段時間,所以只能作爲最後的手段。

+2

我同意一切,除了手動調用System.gc()這被認爲是不好的做法..每個gc(由系統或代碼調用)都會在響應時間(〜15-20ms)內發生小的延遲,這對UI響應總是不利的。 – Ewoks 2012-04-24 14:55:57

+0

我同意。我相應地編輯了我的答案。 – Renard 2012-04-24 16:13:09

+0

全力投票當之無愧:)希望你享受Android的仙境.. :)乾杯 – Ewoks 2012-04-24 20:54:00