摘要:當(dāng)暫停了它的執(zhí)行時(shí),只有將所有引用信息保存在其上下文中,才能枚舉根的集合,這意味著,需要能夠告知那些棧的槽位有一用,那些寄存器持有引用。而真正有機(jī)會(huì)成為暫停點(diǎn)的地方就稱(chēng)作,即能夠安全的枚舉根集合的暫停點(diǎn)。
以 GC safe-point引入GC如何找到不可用的對(duì)象
編寫(xiě)代碼的時(shí)候是可以知道對(duì)象不可用的,但對(duì)于程序來(lái)說(shuō),需要一定的方式來(lái)知曉,可用方法比如:編譯分析,引用計(jì)數(shù),和對(duì)象是否可達(dá)
可達(dá)性分析一個(gè)對(duì)象只要能夠通過(guò)mutator觸達(dá),那么它就是“活”著的。如果Mutator棧的一個(gè)槽位包含了對(duì)象的引用,那么對(duì)象就是直接可觸達(dá)。而從直接可達(dá)對(duì)象可觸達(dá)的對(duì)象必定也是可達(dá)的,因而可達(dá)性分析,只需要找到直接可達(dá)的引用。
直接可達(dá)的引用就是根引用,根引用的集合就是根的集合
mutator的上下文就包含了直接可達(dá)的數(shù)據(jù),所以要獲取對(duì)象根集合就是要找到mutator上下文中的對(duì)象引用,而mutator的上下文指的就是它的棧、它的寄存器文件以及一些線(xiàn)程上特定的數(shù)據(jù)
全局?jǐn)?shù)據(jù)本身也是直接可達(dá)的
可達(dá)性分析為了確保能正確的決定對(duì)象是否存活,GC需要獲取mutator 上下文的一致性快照,然后枚舉所有的根對(duì)象。
這里的一致性指的是 快照的抽取就像只在一個(gè)時(shí)間點(diǎn)發(fā)生,來(lái)避免丟失一些活著的對(duì)象如何獲取 mutator上下文的一致性快照
一種簡(jiǎn)單的方式就是在跟引用的過(guò)程中暫停所有的線(xiàn)程。當(dāng)mutator暫停了它的執(zhí)行時(shí),只有將所有引用信息保存在其上下文中,才能枚舉根的集合,這意味著,mutator需要能夠告知那些棧的槽位有一用,那些寄存器持有引用。如果GC能夠準(zhǔn)確的獲取上述引用信息,它就稱(chēng)作精準(zhǔn)根集合枚舉。
無(wú)法獲取就是不精準(zhǔn)的,以下只講精準(zhǔn)的如何獲取精準(zhǔn)的引用信息枚舉
對(duì)于java來(lái)說(shuō),JIT知曉所有的棧幀信息和寄存器的內(nèi)容,當(dāng)JIT編譯一個(gè)方法時(shí),對(duì)于每條指令,它都可以去保存根引用信息,保存意味著額外的存儲(chǔ)空間,如果要存儲(chǔ)所有的指令就顯得花銷(xiāo)太大,另外在真實(shí)的運(yùn)行過(guò)程中也只有少數(shù)指令才會(huì)成為暫停點(diǎn),因此JIT只需要保存這些指令點(diǎn)的信息就夠了。而真正有機(jī)會(huì)成為暫停點(diǎn)的地方就稱(chēng)作 safe-points,即能夠安全的枚舉根集合的暫停點(diǎn)。
safe-point 定義“A point in program where the state of execution is known by the VM”,即代碼中VM能夠準(zhǔn)確知道執(zhí)行狀態(tài)的位置。
safe-point有多個(gè)種類(lèi)
GC safepoint,要觸發(fā)一次GC,JVM中的所有線(xiàn)程都必須達(dá)到GC safepoint
Deoptimization safepoint,要觸發(fā)一次 deoptimization,需要執(zhí)行deoptimization的線(xiàn)程要到達(dá)safepoint之后才可以開(kāi)始deoptimize
Hotspot中兩者實(shí)現(xiàn)在一起,概念上沒(méi)有直接聯(lián)系,需要數(shù)據(jù)不一樣如何保證mutator會(huì)在 safe-point暫停
當(dāng)GC想要觸發(fā)一次回收時(shí),它會(huì)設(shè)置一個(gè)標(biāo)志,mutator則周期性的去檢查(poll)這個(gè)標(biāo)志,如果檢查到了,就會(huì)立馬暫停,這里的檢查點(diǎn)(poll points)也是安全點(diǎn),由JIT負(fù)責(zé)把poll points放到合適的位置
那些地方適合設(shè)置檢查GC事件的標(biāo)記polling point插入的主要原則是:
polling point應(yīng)該足夠多,防止GC等一個(gè)mutator的暫停太長(zhǎng),導(dǎo)致其他mutator都走在等GC釋放空間,程序整個(gè)等待過(guò)長(zhǎng)
polling point不能太頻繁導(dǎo)致運(yùn)行時(shí)存儲(chǔ)開(kāi)銷(xiāo)過(guò)大
polling本身也是有開(kāi)銷(xiāo)的,不能過(guò)多
權(quán)衡下來(lái)只在必須和必要的地方加
在分配地址的時(shí)候強(qiáng)制添加,因?yàn)榉峙淇臻g很有肯能導(dǎo)致回收,所以這里是一個(gè)安全點(diǎn)
長(zhǎng)時(shí)間的執(zhí)行一般意味著循環(huán)和方法調(diào)用,所以方法調(diào)用和循環(huán)返回最好加上
但是有時(shí)候并不是長(zhǎng)時(shí)間的執(zhí)行,而是長(zhǎng)時(shí)間的空閑,比如 sleep、block,線(xiàn)程在執(zhí)行其他的native函數(shù),這些時(shí)候JVM無(wú)法掌控執(zhí)行能力,也就無(wú)法響應(yīng)GC事件。
不同的JVM選用不同的位置放置safepoint。如何解決sleep/block 帶來(lái)的問(wèn)題
引用safe-region。safe-region是指代碼快中沒(méi)有用到會(huì)變異的部分,這樣的代碼塊中,任何一個(gè)點(diǎn)都可以安全的枚舉根。當(dāng)進(jìn)入到safe-region中時(shí),mutator會(huì)設(shè)置一個(gè)準(zhǔn)備標(biāo)記,在離開(kāi)safe-region區(qū)域之前,會(huì)檢查GC是否已經(jīng)完成了回收,如果沒(méi)有,那么就暫停執(zhí)行,如果有,就可以直接離開(kāi)safe-region區(qū)域,不需要暫停mutator
文章翻譯自 Xiao-Feng Li 博客
rednaxelafx對(duì)safepoint的回答
總結(jié)代碼的執(zhí)行過(guò)程中,如果需要執(zhí)行某些操作,比如GC,deoptimize,等等,必須知道當(dāng)前程序所有線(xiàn)程運(yùn)行到的地方,是否能夠恰好滿(mǎn)足我執(zhí)行對(duì)應(yīng)操作,而不會(huì)對(duì)應(yīng)用程序本身造成損害,這些能夠正確執(zhí)行操作的地方也就是safepoint/saferegion
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/72725.html
摘要:線(xiàn)程安全的概念什么時(shí)候線(xiàn)程不安全怎樣做到線(xiàn)程安全怎么擴(kuò)展線(xiàn)程安全的類(lèi)對(duì)線(xiàn)程安全的支持對(duì)線(xiàn)程安全支持有哪些中的線(xiàn)程池的使用與中線(xiàn)程池的生命周期與線(xiàn)程中斷中的鎖中常見(jiàn)死鎖與活鎖的實(shí)例線(xiàn)程同步機(jī)制顯示鎖使用與原理原理剖析原理中的與原理偏向鎖狀態(tài) showImg(https://segmentfault.com/img/bVblUE9?w=1354&h=1660); 線(xiàn)程安全的概念 showI...
摘要:這個(gè)算法看似不錯(cuò)而且簡(jiǎn)單,不過(guò)存在這一個(gè)致命傷當(dāng)兩個(gè)對(duì)象互相引用的時(shí)候,就永遠(yuǎn)不會(huì)被回收于是引用計(jì)數(shù)算法就永遠(yuǎn)回收不了這兩個(gè)對(duì)象,下面介紹另一種算法。 前言 ? 如果要問(wèn)Java與其他編程語(yǔ)言最大的不同是什么,我第一個(gè)想到的一定就是Java所運(yùn)行的JVM所自帶的自動(dòng)垃圾回收機(jī)制,以下是我學(xué)習(xí)JVM垃圾回收機(jī)制整理的筆記,希望能對(duì)讀者有一些幫助。 哪些內(nèi)存需要回收?what? ? ...
摘要:線(xiàn)程安全需求分析三個(gè)例子都是關(guān)于車(chē)輛追蹤的。他們使用了不同的方式來(lái)保證車(chē)輛追蹤類(lèi)的線(xiàn)程安全性。值得注意的值文檔也是維護(hù)線(xiàn)程安全的重要組成部分。 每個(gè)例子后面有代碼,大家可以先把代碼粘出來(lái)或者開(kāi)兩個(gè)頁(yè)面,先過(guò)一下例子的代碼,然后一邊看分析一遍看代碼,上下拖動(dòng)看的話(huà)效果不好。 歡迎拍磚和補(bǔ)充。 線(xiàn)程安全需求分析 三個(gè)例子都是關(guān)于車(chē)輛追蹤的。他們使用了不同的方式來(lái)保證車(chē)輛追蹤類(lèi)的線(xiàn)程安全性。...
摘要:然而對(duì)于一個(gè)和關(guān)聯(lián)的線(xiàn)程來(lái)說(shuō)在線(xiàn)程被創(chuàng)建和更新他的之前會(huì)有一個(gè)小窗口,因此必須檢查這種情況為線(xiàn)程結(jié)構(gòu)體分配內(nèi)存并創(chuàng)建線(xiàn)程??赡苁?,因此我們耗盡了內(nèi)存太多的活躍線(xiàn)程。代碼執(zhí)行到這,線(xiàn)程還是狀態(tài),因?yàn)榫€(xiàn)程必須被創(chuàng)建者直接啟動(dòng)。 引言 說(shuō)到Thread大家都很熟悉,我們平常寫(xiě)并發(fā)代碼的時(shí)候都會(huì)接觸到,那么我們來(lái)看看下面這段代碼是如何初始化以及執(zhí)行的呢? public class Thread...
摘要:前言本文是一篇簡(jiǎn)短的雜糅本文源自于作者最近的一個(gè)疑問(wèn)為什么在舊版的中偏向鎖的移除一定要在全局安全點(diǎn)進(jìn)行同時(shí)在上個(gè)星期作者參與的一個(gè)項(xiàng)目發(fā)生了一件怪事一個(gè)服務(wù)莫名其妙地不接受任何請(qǐng)求了一切請(qǐng)求都是而查看日志發(fā)現(xiàn)出故障的服務(wù)本身去請(qǐng)求另一個(gè)服務(wù) 前言 本文是一篇簡(jiǎn)短的雜糅. 本文源自于作者最近的一個(gè)疑問(wèn):為什么在舊版的jdk中偏向鎖的移除一定要在全局安全點(diǎn)進(jìn)行?同時(shí)在上個(gè)星期,作者參與的一...
閱讀 3053·2021-10-20 13:46
閱讀 2575·2021-08-12 13:22
閱讀 2754·2019-08-30 15:54
閱讀 2387·2019-08-30 15:53
閱讀 607·2019-08-30 13:47
閱讀 3633·2019-08-23 16:56
閱讀 1782·2019-08-23 13:02
閱讀 1848·2019-08-23 12:25