真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java堆外內(nèi)存回收原理-創(chuàng)新互聯(lián)

堆外內(nèi)存簡(jiǎn)介

DirectByteBuffer 這個(gè)類(lèi)是 JDK 提供使用堆外內(nèi)存的一種途徑,當(dāng)然常見(jiàn)的業(yè)務(wù)開(kāi)發(fā)一般不會(huì)接觸到,即使涉及到也可能是框架(如 Netty、RPC 等)使用的,對(duì)框架使用者來(lái)說(shuō)也是透明的。

創(chuàng)新互聯(lián)建站是專業(yè)的泗水網(wǎng)站建設(shè)公司,泗水接單;提供網(wǎng)站建設(shè)、網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行泗水網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

堆外內(nèi)存優(yōu)勢(shì)

堆外內(nèi)存優(yōu)勢(shì)在 IO 操作上,對(duì)于網(wǎng)絡(luò) IO,使用 Socket 發(fā)送數(shù)據(jù)時(shí),能夠節(jié)省堆內(nèi)存到堆外內(nèi)存的數(shù)據(jù)拷貝,所以性能更高。看過(guò) Netty 源碼的同學(xué)應(yīng)該了解,Netty 使用堆外內(nèi)存池來(lái)實(shí)現(xiàn)零拷貝技術(shù)。對(duì)于磁盤(pán) IO 時(shí),也可以使用內(nèi)存映射,來(lái)提升性能。另外,更重要的幾乎不用考慮堆內(nèi)存煩人的 GC 問(wèn)題。

堆外內(nèi)存創(chuàng)建

我們直接來(lái)看代碼,首先向 Bits 類(lèi)申請(qǐng)額度,Bits 類(lèi)內(nèi)部維護(hù)著當(dāng)前已經(jīng)使用的堆外內(nèi)存值,會(huì) check 當(dāng)前申請(qǐng)的大小與已經(jīng)使用的內(nèi)存大小是否超過(guò)總的堆外內(nèi)存大?。J(rèn)大小與堆內(nèi)存差不多,其實(shí)是有細(xì)微區(qū)別的,拿 CMS GC 來(lái)舉例,它的大小是新生代的大值 - 一個(gè) survivor 的大小 + 老生代的大值),可以使用 -XX:MaxDirectMemorySize 參數(shù)指定堆外內(nèi)存大大小。

Java 堆外內(nèi)存回收原理

如果 check 不通過(guò),會(huì)主動(dòng)執(zhí)行 System.gc(),然后 sleep 100 毫秒,再進(jìn)行 check,如果內(nèi)存還是不足,就拋出 OOM Error。

如果 check 通過(guò),就會(huì)調(diào)用 unsafe.allocateMemory 真正分配內(nèi)存,返回內(nèi)存地址,然后再將內(nèi)存清 0。題外話,這個(gè) unsafe 命名看著是不是很?chē)樔?,這個(gè) unsafe 不是說(shuō)不安全,而是 JDK 內(nèi)部使用的類(lèi),不推薦外部使用,所以叫 unsafe,Netty 源碼內(nèi)部也有類(lèi)似命名。

由于申請(qǐng)內(nèi)存前可能會(huì)調(diào)用 System.gc(),所以謹(jǐn)慎設(shè)置 -XX:+DisableExplicitGC 這個(gè)選項(xiàng),這個(gè)參數(shù)作用是禁止代碼中顯示觸發(fā)的 Full GC。

堆外內(nèi)存回收

cleaner = Cleaner.create(this, new Deallocator (base, size, cap));

看到這段代碼從成員的命名上就應(yīng)該知道,是用來(lái)回收堆外內(nèi)存的。確實(shí),但是它是如何工作的呢?接下來(lái)我們看看 Cleaner 類(lèi)。

Java 堆外內(nèi)存回收原理

Cleaner 類(lèi),內(nèi)部維護(hù)了一個(gè) Cleaner 對(duì)象的鏈表,通過(guò) create(Object, Runnable) 方法創(chuàng)建 cleaner 對(duì)象,調(diào)用自身的 add 方法,將其加入到鏈表中。更重要的是提供了 clean 方法,clean 方法首先將對(duì)象自身從鏈表中刪除,保證只調(diào)用一次,然后執(zhí)行 this.thunk 的 run 方法,thunk 就是由創(chuàng)建時(shí)傳入的 Runnable 參數(shù),也就是說(shuō) clean 只負(fù)責(zé)觸發(fā) Runnable 的 run 方法,至于 Runnable 做什么任務(wù)它不關(guān)心。

那 DirectByteBuffer 傳進(jìn)來(lái)的 Runnable 是什么呢?

Java 堆外內(nèi)存回收原理

Deallocator 類(lèi)的對(duì)象就是 DirectByteBuffer 中的 cleaner 傳進(jìn)來(lái)的 Runnable 參數(shù)類(lèi),我們直接看 run 方法 unsafe.freeMemory 釋放內(nèi)存,然后更新 Bits 里已使用的內(nèi)存數(shù)據(jù)。

接下來(lái)我們關(guān)注各個(gè)環(huán)節(jié)是如何串起來(lái)的?這里主要講兩種回收方式:一種是自動(dòng)回收,一種是手動(dòng)回收。

如何自動(dòng)回收?

Java 是不用用戶去管理內(nèi)存的,所以 Java 對(duì)堆外內(nèi)存 默認(rèn)是自動(dòng)回收的。它是 由 GC 模塊負(fù)責(zé)的,在 GC 時(shí)會(huì)掃描 DirectByteBuffer 對(duì)象是否有有效引用指向該對(duì)象,如沒(méi)有,在回收 DirectByteBuffer 對(duì)象的同時(shí)且會(huì)回收其占用的堆外內(nèi)存。但是 JVM 如何釋放其占用的堆外內(nèi)存呢?如何跟 Cleaner 關(guān)聯(lián)起來(lái)呢?

這得從 Cleaner 繼承了 PhantomReference(虛引用) 說(shuō)起。說(shuō)到 Reference,還有 SoftReference、WeakReference、FinalReference 他們作用各不相同,這里就不展開(kāi)說(shuō)了。

簡(jiǎn)單介紹 PhantomReference,首先虛引用是不會(huì)影響 JVM 去回收其指向的對(duì)象,當(dāng) GC 某個(gè)對(duì)象時(shí),如果有此對(duì)象上還有虛引用對(duì)其引用,會(huì)將 PhantomReference 對(duì)象插入 ReferenceQueue 隊(duì)列。

PhantomReference插入到哪個(gè)隊(duì)列呢?看 PhantomReference 類(lèi)代碼,其繼承自 Reference,Reference 對(duì)象有個(gè) ReferenceQueue 成員,這個(gè)也就是 PhantomReference 對(duì)象插入的 ReferenceQueue 隊(duì)列,此成員如果不由外部傳入就是 ReferenceQueue.NULL。如果需要通過(guò) queue 拿到 PhantomReference 對(duì)象,這個(gè) ReferenceQueue 對(duì)象還是必須由外部傳入。

Java 堆外內(nèi)存回收原理

Reference 類(lèi)內(nèi)部 static 靜態(tài)塊會(huì)啟動(dòng) ReferenceHandler 線程,線程優(yōu)先級(jí)很高,這個(gè)線程是用來(lái)處理 JVM 在 GC 過(guò)程中交接過(guò)來(lái)的 reference。想必經(jīng)常用 jstack 命令,看線程堆棧的同學(xué)應(yīng)該見(jiàn)到過(guò)這個(gè)線程。

我們來(lái)看看 ReferenceHandler 是如何處理的?直接看 run 方法,首先是個(gè)死循環(huán),一直在那不停的干活,synchronized 塊內(nèi)的這段主要是交接 JVM 扔過(guò)來(lái)的 reference(就是 pending),再往下看,很明顯,調(diào)用了 cleaner 的 clean 方法。調(diào)完之后直接 continue 結(jié)束此次循環(huán),這個(gè) reference 并沒(méi)有進(jìn)入 queue,也就是說(shuō) Cleaner 虛引用是不放入 ReferenceQueue。

Java 堆外內(nèi)存回收原理

這塊有點(diǎn)想不通,既然不放入 ReferenceQueue,為什么 Cleaner 類(lèi)還是初始化了這個(gè) ReferenceQueue。

如何手動(dòng)回收?

手動(dòng)回收,就是由開(kāi)發(fā)手動(dòng)調(diào)用 DirectByteBuffer 的 cleaner 的 clean 方法來(lái)釋放空間。由于 cleaner 是 private 反問(wèn)權(quán)限,所以自然想到使用反射來(lái)實(shí)現(xiàn)。

Java 堆外內(nèi)存回收原理

還有另一種方法,DirectByteBuffer 實(shí)現(xiàn)了 DirectBuffer 接口,這個(gè)接口有 cleaner 方法可以獲取 cleaner 對(duì)象。

Java 堆外內(nèi)存回收原理

Netty 中的堆外內(nèi)存池就是使用反射來(lái)實(shí)現(xiàn)手動(dòng)回收方式進(jìn)行回收的。


很多時(shí)候,我們?cè)趯W(xué)習(xí)一門(mén)技術(shù)時(shí)候往往限于眼前而很難突破,也就是通俗意義上的思維固化,這個(gè)時(shí)候你就需要用另一種思維來(lái)打破現(xiàn)狀。學(xué)習(xí)的目的在于擴(kuò)寬自己的視野、發(fā)散自己的思維,以更完備的視角去迎接人生的抉擇。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。


分享文章:Java堆外內(nèi)存回收原理-創(chuàng)新互聯(lián)
URL網(wǎng)址:http://weahome.cn/article/hhpph.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部