Android精品集合

Bitmap.recycle引发的血案

2017-07-20  本文已影响8人  ChineseBoy

在Android中,Bitmap的存储分为两部分,一部分是Bitmap的数据,一部分是Bitmap的引用。
在Android2.3时代,Bitmap的引用是放在堆中的,而Bitmap的数据部分是放在栈中的,需要用户调用recycle方法手动进行内存回收,而在Android2.3之后,整个Bitmap,包括数据和引用,都放在了堆中,这样,整个Bitmap的回收就全部交给GC了,这个recycle方法就再也不需要使用了。

真的,一定不能再用了啊啊啊啊啊。。。。。。。。。。。

现在的SDK中对recycle方法是这样注释的,可以发现,[系统]建议你不要手动去调用,而是让GC来进行处理不再使用的Bitmap。我们可以认为,即使在Android2.3之后的版本中去调用recycle,系统也是会强制回收内存的,只是系统不建议这样做而已。

这个bug的起因是因为我们的一张图片需要旋转,同时可以设置一个旋转角度,老的代码是这样写的:

public static Bitmap rotateBitmap(Bitmap sourceBitmap, int degress, boolean frontCamera) {
        Matrix matrix = new Matrix();
        matrix.postRotate(degress);
        if (frontCamera) {
            if (degress == 90 || degress == 270) {
                matrix.postScale(1, -1);
            } else {
                matrix.postScale(-1, 1);
            }
        }
        Bitmap rotaBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, false);
        return rotaBitmap;
    }

从上面的代码可以很明显的看到我是新create了一个 “新” Bitmap,但是真的新么,不见得啊!!!
按道理来说,bitmap与create出来的rotaBitmap应该是两个对象,当旋转角度正常的时候,确实也是这样,但当旋转角度比较奇葩的时候(这里我旋转了0度),这两个bitmap对象居然变成了同一个!而打开Bitmap.createBitmap的代码,可以发现如下所示的注释:

image.png

The new bitmap may be the same object as source, or a copy may have been made. It is initialized with the same density as the original bitmap.
可能为同一个Bitmap!!!google为了省内存真是666了

当图像的旋转角度小余两个像素点之间的夹角时,图像即使选择也无法显示,因此,系统完全可以认为图像没有发生变化,因此,注释中的情况,就是这种情况了。

血泪史,2.3后不要在用recycle来干事了,GC不是吃屎的。
上一篇下一篇

猜你喜欢

热点阅读