欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Bitmap.recycle引发的血案

程序员文章站 2022-06-08 08:30:45
...

在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的代码,可以发现如下所示的注释:

Bitmap.recycle引发的血案
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不是吃屎的。