我有一些加載到OpenGL紋理圖像的代碼。在這個過程中,我最終加載了3個位圖,因爲我需要加載原始位圖(適合顯示器的尺寸)並根據EXIF數據重新定位位圖。我很快在每個位圖上調用了.recycle()
,但我注意到我的內存似乎沒有改變。我應該在調用Bitmap.recycle()後信任垃圾收集器嗎?
下面是內存監視器顯示:
正如你所看到的,我使用約60MB的內存加載圖像之後。當我旋轉掉落一點的設備時,它會回來。這導致我認爲沒有泄漏,因爲記憶永遠不會超過那個。
當我點擊內存分析器中的GC按鈕時,我的內存佔用量急劇下降到8 MB左右。這是有意義的,因爲在這個過程中產生的三個位圖被回收,所以可以被垃圾回收。然後您可以看到,當我再次旋轉並且重建活動時,內存會立即跳回。
這裏是我的代碼,告訴你爲什麼創建了這麼多的位圖以及它們何時被回收。
void layoutImage() {
...
Bitmap bitmap = loadOrientedConstrainedBitmapWithBackouts(...);
imageTexture = new GLTexture(bitmap);
bitmap.recycle(); // recycle bitmap 2
}
Bitmap loadOrientedConstrainedBitmapWithBackouts(Context context, Uri uri, int maxSize) {
...
Bitmap bitmap = loadBitmapWithBackouts(context, uri, sampleSize); // create bitmap 1
...
Bitmap out = orientBitmap(bitmap, orientation); // create bitmap 2
bitmap.recycle(); // recycle bitmap 1
return out;
}
Bitmap orientBitmap(Bitmap source, int orientation) {
...
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight, matrix, true); // create bitmap 3
}
我真的不知道,這是一個問題,可以這麼說,因爲內存不爬(所以沒有泄漏),但我很好奇,當它停留如此之高。由於強制垃圾收集清除它很好,我應該假設如果系統需要該內存它將在下一個GC通道收集?它一直在運行,我一直在寫這個,並仍坐在舒適的60 MB。
問題1:我可以相信垃圾回收器會在需要時將內存回收嗎?另外,如果我們應該如此審慎地回收我們的位圖,爲什麼很多位圖方法會說「像這樣的新位圖可能與源相同的對象,或者可能已經創建了副本。 「如果它是不同的對象,每次我使用這些方法來回收位圖時,是否真的必須檢查相等性?
問題2:使用位圖創建方法時,是否可能返回相同的位圖或副本,是否需要檢查源和輸出相等性以回收源(如果它是副本)?
編輯:
我試圖與MAT分析這一點,使用堆轉儲在高峯使用(應爲60 MB),但它只報告18.2 MB的使用和沒有什麼不尋常的期待。他們能否以不同的方式閱讀事物
「這使我覺得沒有泄漏」 - 我會建議你使用MAT,而不是猜測。 「如果我們認爲是這樣明智回收我們的位圖」 - 在Android上的現代版本,你應該在'BitmapFactory.Options'爲*重用*你的位圖,通過'inBitmap'。 'recycle()'主要是針對Android 1.x/2.x的一些破解,以幫助GC進行一點。引用當前'Bitmap'源,「這是一個先進的呼叫,並且通常不需要叫,因爲正常的GC進程將釋放該內存的時候有這個位圖不再引用」。 – CommonsWare 2014-11-06 01:28:10
現在,就你而言,你可能不需要重用位圖,這很好。如果MAT表示你的位圖沒有被強制保留,它們最終會被GC'd。發生這種情況的速度取決於各種因素,但如果沒有其他情況發生,如果嘗試分配某些內容失敗,則會發生GC_FOR_ALLOC,這將收集所有可能的垃圾。 – CommonsWare 2014-11-06 01:30:54
回覆:重複使用位圖,我使用採取了源位圖的位圖靜態工廠方法,我不知道怎麼說比較的選項來inBitmap。我也沒有理由保留位圖,因爲我只是使用它們傳遞給OpenGL,然後它們就消失了,直到我必須重新初始化視圖(通過旋轉等)。 – rharter 2014-11-06 02:39:48