GC与native指针
在gc的时候释放native指针。有几个方案,基本是finalize和PhantomReference。
Bitmap
在8.0以后,Bitmap的真实数据是存在native的,所以要有一个绑定到java对象,监听gc并释放native内存的操作。
这里采用的是sun.misc中提供的一个PhantomReference的方式。代码路径如下:
- Bitmap.java#createBitmap
- Bitmap.cpp#Bitmap_creator
- Bitmap.cpp#createBitmap,这里主要是反掉回Bitmap.java的构造函数,用的是LocalRef,也就是说完全不影响gc
- Bitmap.java#<init>,关键代码是
NativeAllocationRegistry registry;
if (fromMalloc) {
registry = NativeAllocationRegistry.createMalloced(
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
} else {
registry = NativeAllocationRegistry.createNonmalloced(
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
}
registry.registerNativeAllocation(this, nativeBitmap);
- NativeAllocationRegistry.java#<init>
- NativeAllocationRegistry.java#registerNativeAllocation,几个关键点:sun.misc.Cleaner(hidden api)、registerNativeAllocation、Reference#reachabilityFence
- registerNativeAllocation,会一层层通知到gc::Heap,看起来是通过native内存过大触发gc
- Reference#reachabilityFence:https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Reference.html#reachabilityFence-java.lang.Object-
- Cleaner: cleaner是PhantomReference的一个子类,只是多保存了一个static Cleaner队列,以及释放时的回调方法(thunk)。而真正调用点在Reference#tryHandlePending,在加入到referenceQueue(如果有)前会调用thunk以完成资源释放