java 层
android 8 以后 bitmap 会被分配到堆外内存,当 bitmap 对象被回收时也必须要释放这块内存。具体原理在 Bitmap 构造函数中
上面涉及会调用到 NativeAllocationRegistry#createXXX 方法,两个方法殊途同归,都是将参数分别记录到 NativeAllocationRegistry 的 freeFunction 与 size 属性中。最关键的是调用 registerNativeAllocation()
Cleaner
上图调用其 clean() 方法,该方法调用 Cleaner 构造函数
private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();
private Cleaner(Object referent, Runnable thunk) {
super(referent, dummyQueue);
this.thunk = thunk;
}
由于 Cleaner 继承 PhantomReference,所以当 bitmap 对象被回收时,会被添加到指定的 queue 中,即上面代码中的 dummyQueue。而 queue 在添加元素的时候会判断是否是 Cleaner,如果是就调用其 clean() 方法
// ReferenceQueue 中
private boolean enqueueLocked(Reference<? extends T> r) {
if (r instanceof Cleaner) {
Cleaner cl = (sun.misc.Cleaner) r;
cl.clean();
r.queueNext = sQueueNextUnenqueued;
return true;
}
//...
return true;
}
因此,代码回到 Cleaner#clean() 方法,该方法也很简单调用 thunk#run(),所以代码回到 CleanerThunk() 中。它的 run 方法很简单
public void run() {
if (nativePtr != 0) {
// 调用 Native 方法
// freeFuntion 就是第一个图中 nativeGetNativeFinalizer() 中的返回值
applyFreeFunction(freeFunction, nativePtr);
registerNativeFree(size);
}
}
native 层
这一层涉及到两个方法,NativeAllocationRegistry#applyFreeFunction() 与 Bitmap#nativeGetNativeFinalizer()。
先看后者,后者定义在 Bitmap.cpp 中
static void Bitmap_destruct(BitmapWrapper* bitmap) {
delete bitmap;
}
// 直接返回的是 Bitmap_destruct 函数地址
static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
}
applyFreeFunction() 源码如下,链接
整个流程也很简单,就是将地址转成函数,然后调用函数,同时传入参数,结束。
总结
跟 native 绑定的内存回收依赖于 NativeAllocationRegistry。android 中除 bitmap 外,跟正则相关的 Matcher 也需要使用该类进行回收