Bitmap有沒有必要主動recycle的問題

大家都知道,Android開發(fā)中,如果涉及到大量bitmap的處理,一個不小心就會發(fā)生OOM。所以,對我來說,當bitmap對象不再需要的時候,及時recycle掉,幾乎是常識一樣自然的事情。
去年做一個項目的時候,剛好讓控件組的同事看了一下我的代碼。他說他們組做過測試,感覺recycle沒什么用。不過控件用到的圖片相對都比較小,所以也不好判斷。
之后看了一下源碼,是這么描述recycle的:

    /**
     * Free the native object associated with this bitmap, and clear the
     * reference to the pixel data. This will not free the pixel data synchronously;
     * it simply allows it to be garbage collected if there are no other references.
     * The bitmap is marked as "dead", meaning it will throw an exception if
     * getPixels() or setPixels() is called, and will draw nothing. This operation
     * cannot be reversed, so it should only be called if you are sure there are no
     * further uses for the bitmap. This is an advanced call, and normally need
     * not be called, since the normal GC process will free up this memory when
     * there are no more references to this bitmap.
     */
    public void recycle() {
        if (!mRecycled && mNativePtr != 0) {
            if (nativeRecycle(mNativePtr)) {
                // return value indicates whether native pixel object was actually recycled.
                // false indicates that it is still in use at the native level and these
                // objects should not be collected now. They will be collected later when the
                // Bitmap itself is collected.
                mBuffer = null;
                mNinePatchChunk = null;
            }
            mRecycled = true;
        }
    }

這是API 25的代碼,可以看到注釋里面有這么一句,“This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references.”。
我的理解就是,recycle確實不是立即回收對應bitmap的內存,因為不是synchronously嘛。

那么,不調用recycle行嗎?

特別是上面的注釋里面寫了:

* This is an advanced call, and normally need
* not be called, since the normal GC process will free up this memory when
* there are no more references to this bitmap.

那么,查了一些文檔后,我的結論是:可以不調用recycle,但是要及時把對bitmap的引用置為null。至于以前都要求對bitmap主動recycle,不要等GC,是有其歷史原因的。

我是通過這篇帖子 《Bitmap.recycle引發(fā)的血案 》http://www.itdecent.cn/p/b5c8e98ff5b0 找到了官方的兩個說明網(wǎng)頁:

https://developer.android.google.cn/topic/performance/graphics/manage-memory.html#recycle

https://developer.android.google.cn/topic/performance/graphics/cache-bitmap.html

而從上面的鏈接中,可以得到如下信息:

  1. Android中,Bitmap的對象在內存中可以分為兩部分,一個是Bitmap對象本身,另一個是像素數(shù)據(jù)。
    并且,在Android 2.3.3 以前,像素數(shù)據(jù)與對象本身分開存儲,像素數(shù)據(jù)存儲在native層;對象存儲在java層。顯然,像素數(shù)據(jù)才是內存占用的大頭。并且,像素數(shù)據(jù)什么時候回收是沒有保證的。這時也是最容易觸發(fā) OOM 的時候。
    但是,在Android 3.0 以后,像素數(shù)據(jù)與Bitmap對象數(shù)據(jù)一起關聯(lián)存儲在Dalvik堆中。所以,這個時候,就可以考慮用GC來自動回收Bitmap的內存了。

On Android 2.3.3 (API level 10) and lower, the backing pixel data for a bitmap is stored in native memory. It is separate from the bitmap itself, which is stored in the Dalvik heap. The pixel data in native memory is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash. As of Android 3.0 (API level 11), the pixel data is stored on the Dalvik heap along with the associated bitmap.

  1. Android 2.2 中,GC發(fā)生的時候回造成應用線程停頓,也就是可能會卡。
    但是,Android 2.3 里面更新了GC機制,應該不會再造成線程停止了。

On Android Android 2.2 (API level 8) and lower, when garbage collection occurs, your app's threads get stopped. This causes a lag that can degrade performance. Android 2.3 adds concurrent garbage collection, which means that the memory is reclaimed soon after a bitmap is no longer referenced.

  1. 所以,作為完整性的結論,官方說明是:
    a. Android 2.3.3 以前的版本,在確認Bitmap已經不再使用的情況下,推薦主動調用recycle。
    b. Android 3.0 以后,將Bitmap對象的引用及時置null就行了,應該不需要再主動調用recycle方法了。當然,調用,應該也沒什么問題。
    c. 進一步的,Android 3.0 以后,可以通過設置 BitmapFactory.Options.inBitmap 來復用原來的Bitmap內存。當然,什么時候可以復用,什么時候不能,這就是另一個話題了。比如,當圖片分辨率相同的情況下,在BitmapFactory的decode方法中,應該是會復用的。
    并且,官方推薦用 Glide 或者 LruCache 來做圖片緩存管理。這個時候就可以參考 https://developer.android.google.cn/topic/performance/graphics/cache-bitmap.html 了。

那么,現(xiàn)在還有人要兼容 Android 3.0 以前的版本嗎?我想是沒有了,所以已經不需要主動調用recycle方法。

不過,以上都是理論分析,主動調用recycle會不會比等待GC更有效一點呢?比如,主動降內存。畢竟,當一個圖片列表中的Bitmap都很大的時候,會不會發(fā)生GC不及時的情況?這就不知道了,等哪天寫個demo驗證一下吧。
但是,如果開發(fā)過程中正好用到了這種情況,我覺得可以大膽的不去調用recycle,注意看一下內存變化就行了。如果真的因此而不能通過測試,大不了再把recycle加回來好了。特別是對大部分人來說,圖片列表里面的圖片分辨率也不會搞那么大的。

寫在最后的最后,上面貼的官方鏈接,是看別人貼出來,然后我一個一個跳轉過去的。如果直接進入Android開發(fā)者首頁,我就不知道有什么方法能找到它們了。因為,不像API指南,或者那一套Training,可以直接點擊菜單跳轉過去。這幾個鏈接,反正我是找不到從界面跳轉進去的入口。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容