在NIO技术中,使用allocateDirect()方法可以创建直接内存;如何释放该内存呢?
文章目录(1)通过手动释放内存(Cleaner+虚引用)
(2)交给JVM进行处理(Full GC)
- 1.直接内存的创建与销毁
- 2.通过Cleaner+虚引用完成堆外内存回收
- 3.总结创建与销毁流程
- 4.如何一步步顺序解读源码流程
- 5.使用直接内存的利弊分析
base = UNSAFE.allocateMemory(size);
在DirectByteBuffer类构造方法中,主要通过allocateMemory方法完成堆外内存的创建,这个方法是Unsafe类中,这个类是干什么的呢?通过名字我们可以也可以看出这个类是不安全的,也就是它是能够直接 *** 作堆外内存,超出了JVM的管辖范围!
UNSAFE.freeMemory(address);
需要注意的是通过Unsafe开辟的直接内存,需要通过调用freeMemory手动回收(当然帮你写了)
2.通过Cleaner+虚引用完成堆外内存回收Java对象有四种引用方式:强软弱虚
虚引用PhantomReference一般来说极少使用,而且它不能单独使用,它需要和引用队列 ReferenceQueue一块使用
首先分析allocateDirect()方法底层(DirectByteBuffer类)
通过它的构造方法可以看出创建了Cleaner对象和Deallocator对象,首先分析Cleaner对象,通过看它的源码可以得出,它的底层维护了一个双向链表,当Cleaner对象初始化时,就会加入到这个Cleaner双向链表中(而且是安全的,使用了Synchronized,Cleaner类继承了虚引用)
public static Cleaner create(Object ob, Runnable thunk) { if (thunk == null) return null; return add(new Cleaner(ob, thunk)); }
当DirectByteBuffer对象不存在时,Cleaner对象不再处于引用链中,等到下一次GC时,Cleaner会被加入到ReferenceQueue队列中,并执行clean方法;将将自身从Cleaner双向链表中移除(remove),然利用多态调用了Deallocator类中的run方法释放内存
public void clean() { if (!remove(this)) return; try { thunk.run(); } catch (final Throwable x) { AccessController.doPrivileged(new PrivilegedAction<>() { public Void run() { if (System.err != null) new Error("Cleaner terminated abnormally", x) .printStackTrace(); System.exit(1); return null; }}); } }
public void run() { if (address == 0) { // Paranoia return; } UNSAFE.freeMemory(address); address = 0; Bits.unreserveMemory(size, capacity); }3.总结创建与销毁流程
分析下图总结流程(来源百度图片)
初始时,创建了一个DirectByteBuffer对象,在DirectByteBuffer的构造函数中创建了一个Cleaner对象和Deallocator对象;Cleaner对象初始化时将自身加入到了链表中;一旦DirectByteBuffer对象被回收,那么下次GC时Cleaner(继承了虚引用)对象会被放到ReferenceQueue队列中并执行clean方法(多态调用了Deallocator中的run方法释放内存)
4.如何一步步顺序解读源码流程
(1)ByteBuffer抽象类的allocateDirect方法
(2)DirectByteBfufer的构造方法
(3)Cleaner类的create方法
(4)Cleaner类的add方法
(5)回到第二步
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
(6)Deallocator类的构造方法
5.使用直接内存的利弊分析将Cleaner类中分配的直接内存的地址、大小等进行复制,因为这个类的run方法是进行内存回收的根方法。
使用直接内存肯定也有坏处,否者还有堆内存什么事;使用直接内存不受JVM的管辖,稍有不慎容易造成内存泄漏!当然使用直接内存减少了GC的时间(交给了 *** 作系统进行管理),另一方面与磁盘交互时使用直接内存减少了复制 *** 作,效率得到提高。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)