【大白话系列】深入浅出Cleaner+虚引用完成堆外内存的回收
在NIO技術(shù)中,使用allocateDirect()方法可以創(chuàng)建直接內(nèi)存;如何釋放該內(nèi)存呢?
(1)通過(guò)手動(dòng)釋放內(nèi)存(Cleaner+虛引用)
(2)交給JVM進(jìn)行處理(Full GC)
文章目錄
- 1.直接內(nèi)存的創(chuàng)建與銷(xiāo)毀
- 2.通過(guò)Cleaner+虛引用完成堆外內(nèi)存回收
- 3.總結(jié)創(chuàng)建與銷(xiāo)毀流程
- 4.如何一步步順序解讀源碼流程
- 5.使用直接內(nèi)存的利弊分析
1.直接內(nèi)存的創(chuàng)建與銷(xiāo)毀
base = UNSAFE.allocateMemory(size);在DirectByteBuffer類構(gòu)造方法中,主要通過(guò)allocateMemory方法完成堆外內(nèi)存的創(chuàng)建,這個(gè)方法是Unsafe類中,這個(gè)類是干什么的呢?通過(guò)名字我們可以也可以看出這個(gè)類是不安全的,也就是它是能夠直接操作堆外內(nèi)存,超出了JVM的管轄范圍!
UNSAFE.freeMemory(address);需要注意的是通過(guò)Unsafe開(kāi)辟的直接內(nèi)存,需要通過(guò)調(diào)用freeMemory手動(dòng)回收(當(dāng)然幫你寫(xiě)了)
2.通過(guò)Cleaner+虛引用完成堆外內(nèi)存回收
Java對(duì)象有四種引用方式:強(qiáng)軟弱虛
虛引用PhantomReference一般來(lái)說(shuō)極少使用,而且它不能單獨(dú)使用,它需要和引用隊(duì)列 ReferenceQueue一塊使用
首先分析allocateDirect()方法底層(DirectByteBuffer類)
通過(guò)它的構(gòu)造方法可以看出創(chuàng)建了Cleaner對(duì)象和Deallocator對(duì)象,首先分析Cleaner對(duì)象,通過(guò)看它的源碼可以得出,它的底層維護(hù)了一個(gè)雙向鏈表,當(dāng)Cleaner對(duì)象初始化時(shí),就會(huì)加入到這個(gè)Cleaner雙向鏈表中(而且是安全的,使用了Synchronized,Cleaner類繼承了虛引用)
當(dāng)DirectByteBuffer對(duì)象不存在時(shí),Cleaner對(duì)象不再處于引用鏈中,等到下一次GC時(shí),Cleaner會(huì)被加入到ReferenceQueue隊(duì)列中,并執(zhí)行clean方法;將將自身從Cleaner雙向鏈表中移除(remove),然利用多態(tài)調(diào)用了Deallocator類中的run方法釋放內(nèi)存
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) {// Paranoiareturn;}UNSAFE.freeMemory(address);address = 0;Bits.unreserveMemory(size, capacity);}3.總結(jié)創(chuàng)建與銷(xiāo)毀流程
分析下圖總結(jié)流程(來(lái)源百度圖片)
初始時(shí),創(chuàng)建了一個(gè)DirectByteBuffer對(duì)象,在DirectByteBuffer的構(gòu)造函數(shù)中創(chuàng)建了一個(gè)Cleaner對(duì)象和Deallocator對(duì)象;Cleaner對(duì)象初始化時(shí)將自身加入到了鏈表中;一旦DirectByteBuffer對(duì)象被回收,那么下次GC時(shí)Cleaner(繼承了虛引用)對(duì)象會(huì)被放到ReferenceQueue隊(duì)列中并執(zhí)行clean方法(多態(tài)調(diào)用了Deallocator中的run方法釋放內(nèi)存)
4.如何一步步順序解讀源碼流程
(1)ByteBuffer抽象類的allocateDirect方法
(2)DirectByteBfufer的構(gòu)造方法
(3)Cleaner類的create方法
(4)Cleaner類的add方法
(5)回到第二步
(6)Deallocator類的構(gòu)造方法
將Cleaner類中分配的直接內(nèi)存的地址、大小等進(jìn)行復(fù)制,因?yàn)檫@個(gè)類的run方法是進(jìn)行內(nèi)存回收的根方法。
5.使用直接內(nèi)存的利弊分析
使用直接內(nèi)存肯定也有壞處,否者還有堆內(nèi)存什么事;使用直接內(nèi)存不受JVM的管轄,稍有不慎容易造成內(nèi)存泄漏!當(dāng)然使用直接內(nèi)存減少了GC的時(shí)間(交給了操作系統(tǒng)進(jìn)行管理),另一方面與磁盤(pán)交互時(shí)使用直接內(nèi)存減少了復(fù)制操作,效率得到提高。
總結(jié)
以上是生活随笔為你收集整理的【大白话系列】深入浅出Cleaner+虚引用完成堆外内存的回收的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深入浅出在NIO技术中,如何理解直接缓冲
- 下一篇: 【大白话系列】带你进入网络的世界【都说计