前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Bitmap.recycle引发的血案

Bitmap.recycle引发的血案

作者头像
用户1907613
发布2018-07-20 16:14:36
3K0
发布2018-07-20 16:14:36
举报
文章被收录于专栏:Android群英传Android群英传

从Bitmap.recycle说起

在Android中,Bitmap的存储分为两部分,一部分是Bitmap的数据,一部分是Bitmap的引用。

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

然而……

现在的SDK中对recycle方法是这样注释的,如图所示:

bitmap.png

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

鄙司代码有些是从Android2.3出来的,因此很多地方还在使用Bitmap.recycle。通常情况下,这也没什么问题,但是,今天遇到一个bug引发了Bitmap.recycle的血案。

起因

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

代码语言:javascript
复制
ImageView imageView = (ImageView) findViewById(R.id.test);
Matrix matrix = new Matrix();
matrix.setRotate(0.013558723994643297f);Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Bitmap targetBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);if (!bitmap.isRecycled()) {
    bitmap.recycle();
}
imageView.setImageBitmap(targetBmp);

除了中间的0.013558723994643297f这串比较奇葩的数据(当然,正常情况下都是20、30这样正常的数),其它都是比较正常的代码。

但实际上,只要一运行这段代码,程序就会崩溃,错误原因如下所示:

代码语言:javascript
复制
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.xys.preferencetest, PID: 30512
                  java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@1a50ff6b

这个问题一看就知道是由于Bitmap被调用recycle方法回收后,又调用了Bitmap的一些方法而导致的。可是,代码中可以发现我们recycle的是bitmap而不是通过Bitmap.createBitmap重新生成的targetBmp,为什么会报这个exception呢?

注释

按道理来说,bitmap与create出来的targetBmp应该是两个对象,当旋转角度正常的时候,确实也是这样,但当旋转角度比较奇葩的时候,这两个bitmap对象居然变成了同一个!而打开Bitmap.createBitmap的代码,可以发现如下所示的注释:

bitmap2.png

这里居然写着:The new bitmap may be the same object as source, or a copy may have been made.

看来还是真有可能为同一个对象的!

猜测

经过几次尝试,发现只有在角度很小很小的时候,才会出现这个情况,两个bitmap是同一个对象,因此,我只能这样猜测,当角度过小时,系统认为这是一张图片,没有发生变化,那么系统就直接引用同一个对象来进行操作,避免内存浪费。那么这个角度是怎么来的呢?继续猜测,如图所示:

bitmap3.png

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

我还没有来得及继续验证,希望大家可以一起讨论下~有说的不对的还请指教。

然而……

然而,教训是,在不兼容Android2.3的情况下,别在使用recycle方法来管理Bitmap了,那是GC的事!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-01-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 从Bitmap.recycle说起
  • 然而……
    • 起因
      • 注释
        • 猜测
          • 然而……
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档