看看Bitmap源码中recycle 做了什么
PS:源码查看工具网站:AndroidXref、grepCode
起因
在Bitmap调用recycle之后再去使用,会有invalid Bitmap的异常导致应用崩溃,实际项目中其实是碰到了tgkill的Native代码崩溃的堆栈信息:
分析Bitmap getGenerationId在源码中的调用情况:(git clone Framework 源码之后用sublimeText搜索得如下结果,txt文件已过滤)
绿色框中的代码因为是surface的API,或者是JavaDoc的注释,可以忽略不计,可以看到有效调用就是关于Notification的调用;
结合GP后台的崩溃占用情况(>7.0占比较高,6.0亦有发生),查阅AndroidDeveloper的v6.0 changeLog,发现有这么一条:
看到其中关键信息 ==reuse Notification.Builder instance==,但鉴于其它App没有出现这种级别的问题,所以另谋其它出路;
剩下的就只剩Bitmap了
Bitmap recycle做了什么
Bitmap.cpp
source code on xRef: http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/jni/android/graphics/Bitmap.cpp
1 | 782static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { |
1 | 168void Bitmap::freePixels() { |
1 | 176void Bitmap::doFreePixels() { |
注意析构函数:
1 | 164 Bitmap::~Bitmap() { |
还需注意到代码:
结合Bitmap.cpp的其它代码,只有在Bitmap recycle之后又拿来使用才会出现这个assertValid断言错误,遂将矛头指向Bitmap recycle
不调用recycle()会怎样?
Android2.3(API 11)之前,Bitmap开辟的内存位于native Stack,需要手动调用recycle进行释放,而2.3之后属于VM的heap,系统GC会自动处理。
而我们在2.3之后的系统中调用Bitmap的recycle,唯一的作用,就是把Bitmap释放的动作提前了,私以为,仅有的效用是会降低OOM发生的概率
这一点也可以从Bitmap AndroidAPI解释网页上看出一点端倪
this is an advanced call, and normally need not be called…
策略
在所有会调用Bitmap.recycle()的地方,对相应的recycle状态检查,如果发现有recycle之后仍然在使用的地方,则直接抛出异常,暴露问题,就像这样:
这样,在Monkey测试覆盖面够广时,就可以预期暴露出问题所在了;
关于Bitmap的检查,还有一种思路是使用hook方式进行,这样还可以对第三方依赖lib进行检查,后期如果应用这种方式,我再补充一篇
Ref:
- bitmap recycle不当调用引发的问题 http://www.jianshu.com/p/b5c8e98ff5b0
- Bitmap source Code:https://android.googlesource.com/platform/frameworks/base/+/47fb191/core/jni/android/graphics/Bitmap.cpp;(GrepCode网站上5.0r1的Bitmap sourcecode)http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/5.0.0_r2-robolectric-0/android/graphics/Bitmap.java;(AndroidXref网站上的Bitmap 7.1.1 sourcecode)http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/jni/android/graphics/Bitmap.cpp#896
- Bitmap API 解释on AndroidDeveloper:https://stuff.mit.edu/afs/sipb/project/android/docs/reference/android/graphics/Bitmap.html#recycle()