Bitmap 回收

111 阅读1分钟

java 层

android 8 以后 bitmap 会被分配到堆外内存,当 bitmap 对象被回收时也必须要释放这块内存。具体原理在 Bitmap 构造函数中

image.png

上面涉及会调用到 NativeAllocationRegistry#createXXX 方法,两个方法殊途同归,都是将参数分别记录到 NativeAllocationRegistry 的 freeFunction 与 size 属性中。最关键的是调用 registerNativeAllocation()

image.png

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() 源码如下,链接

image.png

整个流程也很简单,就是将地址转成函数,然后调用函数,同时传入参数,结束。

总结

跟 native 绑定的内存回收依赖于 NativeAllocationRegistryandroid 中除 bitmap 外,跟正则相关的 Matcher 也需要使用该类进行回收