2013-02-01 43 views
4

當我儘量減少我的Android應用程序約4〜5次,我總是得到以下錯誤:安卓:內存不足錯誤

02-01 19:24:11.980: E/dalvikvm-heap(22362): Out of memory on a 3686416-byte allocation. 
02-01 19:24:12.000: E/dalvikvm(22362): Out of memory: Heap Size=62755KB, Allocated=55237KB, Limit=65536KB 
02-01 19:24:12.000: E/dalvikvm(22362): Extra info: Footprint=62435KB, Allowed Footprint=62755KB, Trimmed=2144KB 
02-01 19:24:12.000: E/Bitmap_JNI(22362): Create Bitmap Failed.  
02-01 19:24:12.000: E/Bitmap_JNI(22362): Failed to create SkBitmap! 
02-01 19:24:12.000: E/AndroidRuntime(22362): FATAL EXCEPTION: main 
02-01 19:24:12.000: E/AndroidRuntime(22362): java.lang.OutOfMemoryError: (Heap Size=62755KB, Allocated=55237KB) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at android.graphics.Bitmap.nativeCreateScaledBitmap(Native Method) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:744) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at de.vauge.mb.Utils.getResizedBitmap(Utils.java:56) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at de.vauge.mb.MenuView.initialize(MenuView.java:74) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at de.vauge.mb.MenuView$1.handleMessage(MenuView.java:137) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at android.os.Handler.dispatchMessage(Handler.java:99) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at android.os.Looper.loop(Looper.java:156) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at android.app.ActivityThread.main(ActivityThread.java:5045) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at java.lang.reflect.Method.invokeNative(Native Method) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at java.lang.reflect.Method.invoke(Method.java:511) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
02-01 19:24:12.000: E/AndroidRuntime(22362): at dalvik.system.NativeStart.main(Native Method) 

我的應用程序由具有7種不同的,自我只有一個活動(它們都包含一些位圖),當它們不需要的時候它們會被切換到不可見的狀態(可能不是很好的風格,但它直到現在對我都有效......)。這些視圖中的每一個都有一個destroy()函數,用於循環使用它的所有位圖,MainActivity的onDestroy()調用所有這些destroy()函數。此外,我沒有使用任何靜態位圖。

那麼,除了回收所有Bitmap並且不使用靜態位圖之外,還有什麼可以嘗試的嗎?

回答

9

好吧。 Android上的位圖可能有點棘手。你能給出更好的關於位圖來源和它們大小的信息嗎?

否則,我會建議考慮這些事情:

  1. 如果要加載遠程圖像,檢查fresco。您還可以查看Picasso。我個人以前喜歡ImageLoader,但它不再被維護。

  2. 如果您使用inPurgable標誌曾經是推薦選項,請嘗試找到一種方法,因爲它實際上會爲每個圖像分配更多的內存。

  3. 如果您經常對小型本地資源進行解碼,請考慮將繪圖保存在散列圖中,並在需要時重複使用它們。少了GC。

  4. 如果你關心你的子類應用程序,你可以使用OnLowMemory電話,知道什麼時候你可能真的需要清理(主要用於調試好,並不是真實的生活情況)......如果這還不算晚... :)

  5. 看看Chris Banes的博客。 This是一個非常有趣的內存緩存解決方案

  6. 實現您需要和可能時調用的內存修剪器。

  7. 另一個令人驚奇的優化是當你可以使用較小的對象時...考慮你的最小數據模型和圖像大小,並嘗試爲這些應用程序提供一致的API。

0

請確定你正在加載它們在onCreate()而不是在onStart()onResume()。這聽起來像是他們每次恢復時都會重新加載,但它們並未被銷燬,因爲onDestroy()在您最小化應用程序時未被調用。

+0

MHH ..他們在onCreate()中加載。我剛剛意識到,最小化它們並不是問題。只有當我鎖定我的屏幕,應用程序似乎被銷燬或至少onDestroy()被稱爲,當我鎖定和解鎖我的手機幾次,錯誤發生......任何想法? – vauge

+0

你確定'onDestroy()'在你鎖定手機時被調用嗎? 無論哪種方式,如果你只是在'onCreate()'中創建它們,應該沒有關係。我唯一能想到的其他事情就是製作一個日誌打印,在每個位圖上調用'isRecycled()'以確保它們實際上被回收。 – Tim

0

如果圖像在本地設備上(即與您的代碼合併或來自用戶圖像庫),那麼我可以選擇不讓它們簡單地隱藏或不隱藏,而只是將它們放在從磁盤飛行。事實證明,所有這些設備基本上都是基於閃存的,這與主軸磁盤相比非常快。用戶很可能無法感受到磁盤IO對圖像的性能影響。

這種方式也可以限制您在任何時候在內存中保存的AMOUNT圖像。

我同意你應該看看Tim的評估。

1

對於#3,從本·馬克斯評論我maked兩個有用類:

public abstract class SoftReferenceStorage<K, V>{ 
private static HashMap<Object, SoftReference<Object>> objectsHash = new HashMap<Object, SoftReference<Object>>(); 

@SuppressWarnings("unchecked") 
public V get(K key) { 
    if (objectsHash.containsKey(key)) { 
     SoftReference<Object> ref = objectsHash.get(key); 
     if (ref.get() == null) { 
      objectsHash.put(key, new SoftReference<Object>(createValueForKey(key))); 
      return (V)objectsHash.get(key).get(); 
     } else { 
      return (V)ref.get(); 
     } 
    } else { 
     objectsHash.put(key, new SoftReference<Object>(createValueForKey(key))); 
     return (V)objectsHash.get(key).get(); 
    } 
} 

protected abstract V createValueForKey(K key); 
} 

public class FrequentlyUsedBitmapResources extends SoftReferenceStorage<Integer, Bitmap>{ 
private static FrequentlyUsedBitmapResources instance = null; 

private Resources resources; 

public FrequentlyUsedBitmapResources(Resources resources) { 
    super(); 
    this.resources = resources; 
} 

public static FrequentlyUsedBitmapResources getInstance() { 
    if (instance == null) { 
     instance = new FrequentlyUsedBitmapResources(HiDriveApp.getContext().getResources()); 
    } 
    return instance; 
} 

@Override 
protected Bitmap createValueForKey(Integer resId) { 
    return BitmapFactory.decodeResource(resources, resId); 
} 
} 

可以像使用:

Bitmap b = FrequentlyUsedBitmapResources.getInstance().get(R.drawable.overview_photo_placeholder);