2014-11-06 42 views
1

我有一些加載到OpenGL紋理圖像的代碼。在這個過程中,我最終加載了3個位圖,因爲我需要加載原始位圖(適合顯示器的尺寸)並根據EXIF數據重新定位位圖。我很快在每個位圖上調用了.recycle(),但我注意到我的內存似乎沒有改變。我應該在調用Bitmap.recycle()後信任垃圾收集器嗎?

下面是內存監視器顯示:

memory monitor

正如你所看到的,我使用約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的使用和沒有什麼不尋常的期待。他們能否以不同的方式閱讀事物

enter image description here

+0

「這使我覺得沒有泄漏」 - 我會建議你使用MAT,而不是猜測。 「如果我們認爲是這樣明智回收我們的位圖」 - 在Android上的現代版本,你應該在'BitmapFactory.Options'爲*重用*你的位圖,通過'inBitmap'。 'recycle()'主要是針對Android 1.x/2.x的一些破解,以幫助GC進行一點。引用當前'Bitmap'源,「這是一個先進的呼叫,並且通常不需要叫,因爲正常的GC進程將釋放該內存的時候有這個位圖不再引用」。 – CommonsWare 2014-11-06 01:28:10

+0

現在,就你而言,你可能不需要重用位圖,這很好。如果MAT表示你的位圖沒有被強制保留,它們最終會被GC'd。發生這種情況的速度取決於各種因素,但如果沒有其他情況發生,如果嘗試分配某些內容失敗,則會發生GC_FOR_ALLOC,這將收集所有可能的垃圾。 – CommonsWare 2014-11-06 01:30:54

+0

回覆:重複使用位圖,我使用採取了源位圖的位圖靜態工廠方法,我不知道怎麼說比較的選項來inBitmap。我也沒有理由保留位圖,因爲我只是使用它們傳遞給OpenGL,然後它們就消失了,直到我必須重新初始化視圖(通過旋轉等)。 – rharter 2014-11-06 02:39:48

回答

3

問題1:我可以只相信,如果需要,垃圾收集器將內存回來?

是的。如果傳入的引用被清除,垃圾收集器將在需要時獲取內存(通常用於新分配)。調用recycle()不會幫助這個過程,也不會讓它發生得更快。

recycle()方法存在是因爲Bitmap對象沒有沿堆直到Android 3.0的計數;所以這個方法對GC的幫助很有幫助,因爲它沒有記錄內存對堆的​​記錄。在3.0+版本中,內存是針對堆進行跟蹤的,因此這種額外的簿記已不再需要。

問題2:當使用位圖創建方法,可能會或可能不會返回相同的位圖或副本,做我需要檢查源和輸出平等來回收來源,如果它是一個副本?

createBitmap()方法將返回相同的對象,如果:

  • 源是不可變的
  • xy均爲零
  • widthheight匹配源的寬度和高度
  • 沒有應用變換矩陣

因爲它看起來像你傳遞一個變換矩陣,你總是會得到一個副本,除非矩陣是出於某種原因的身份。但是,除非您仍然支持2.x版本,否則不需要recycle()