Bitmap有没有必要主动recycle的问题

大家都知道,Android开发中,如果涉及到大量bitmap的处理,一个不小心就会发生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引发的血案 》http://www.jianshu.com/p/b5c8e98ff5b0 找到了官方的两个说明网页:

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对象本身,另一个是像素数据。
    并且,在Android 2.3.3 以前,像素数据与对象本身分开存储,像素数据存储在native层;对象存储在java层。显然,像素数据才是内存占用的大头。并且,像素数据什么时候回收是没有保证的。这时也是最容易触发 OOM 的时候。
    但是,在Android 3.0 以后,像素数据与Bitmap对象数据一起关联存储在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发生的时候回造成应用线程停顿,也就是可能会卡。
    但是,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 了。

那么,现在还有人要兼容 Android 3.0 以前的版本吗?我想是没有了,所以已经不需要主动调用recycle方法。

不过,以上都是理论分析,主动调用recycle会不会比等待GC更有效一点呢?比如,主动降内存。毕竟,当一个图片列表中的Bitmap都很大的时候,会不会发生GC不及时的情况?这就不知道了,等哪天写个demo验证一下吧。
但是,如果开发过程中正好用到了这种情况,我觉得可以大胆的不去调用recycle,注意看一下内存变化就行了。如果真的因此而不能通过测试,大不了再把recycle加回来好了。特别是对大部分人来说,图片列表里面的图片分辨率也不会搞那么大的。

写在最后的最后,上面贴的官方链接,是看别人贴出来,然后我一个一个跳转过去的。如果直接进入Android开发者首页,我就不知道有什么方法能找到它们了。因为,不像API指南,或者那一套Training,可以直接点击菜单跳转过去。这几个链接,反正我是找不到从界面跳转进去的入口。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容