JVM中如何做到STW使程序暫停
為什么需要STW呢?試想你媽給你打掃房間的場(chǎng)景:把你攆出去,關(guān)上門,打掃干凈,打開(kāi)門,數(shù)落你,揍你…一套標(biāo)準(zhǔn)化流程后,房間干凈了。打完你,***心情變好了,打麻將都能多贏點(diǎn)。
這里面有個(gè)關(guān)鍵環(huán)節(jié):把你攆出去。盡管在打掃房間的過(guò)程中你可能不會(huì)制造垃圾,但是你的存在就有這個(gè)風(fēng)險(xiǎn),所以必須把你攆出去。這話不是我說(shuō)的,是從***行為中揣摩出來(lái)的。^_^
試想,如果不把你攆出去,你媽打掃垃圾的同時(shí),你又陸陸續(xù)續(xù)制造了垃圾,那這場(chǎng)打掃房間的行動(dòng)是不是變成了無(wú)法結(jié)束的行動(dòng)啊?;蛘叩侥硞€(gè)時(shí)間點(diǎn),你媽打掃了一半走了,丟下一句話:朽木不可雕也,孺子不可教也。
垃圾收集器也是一樣的,為了保證清理垃圾的完整性,在某些環(huán)節(jié),就會(huì)STW。比如所有垃圾收集器中都有的一個(gè)階段:初始階段,即掃描根對(duì)象,需要STW。小伙伴門看過(guò)的幾乎所有資料,講到這基本就沒(méi)了對(duì)吧。但這不是子牙老師我的風(fēng)格,咱們接著往后面說(shuō)。
STW
JVM中要做到STW是很難的。為什么這么說(shuō)呢?因?yàn)樾枰紤]很多很多因素。
一、JVM中存在多種類型的會(huì)發(fā)生改變內(nèi)存行為的線程:
執(zhí)行業(yè)務(wù)邏輯的用戶線程
執(zhí)行native方法的Java線程
執(zhí)行垃圾收集的GC線程
執(zhí)行即時(shí)編譯的JIT線程
二、每種類型的線程個(gè)數(shù),在需要STW的那一刻,可能都不止一個(gè)。
三、每種類型的線程,在需要STW的那一刻,執(zhí)行到的代碼位置也未可知。
四、每種類型的線程阻塞的點(diǎn)還不能隨機(jī)。因?yàn)榫€程在阻塞前需要更新OopMap。
OopMap是什么?你可以理解成是記錄這個(gè)線程一路跑下來(lái)經(jīng)歷過(guò)的所有Java對(duì)象的集合。為什么要有OopMap呢?因?yàn)闆](méi)有的話,你就得掃描整個(gè)棧,去查找根對(duì)象。
這里說(shuō)的只是查找根對(duì)象的一種情況哈,勿抬桿,我會(huì)記仇。^_^
如何暫停線程
聽(tīng)我這么一分析,好像確實(shí)很復(fù)雜哈。那如果是你來(lái)實(shí)現(xiàn),你會(huì)怎么解決呢?小伙伴門可以想一想。經(jīng)常想這樣有深度的問(wèn)題,有利于提高你的思考深度。
我們還是來(lái)看看JVM是如何高明地解決的吧。
如果線程隨便哪個(gè)位置阻塞都合適,這個(gè)問(wèn)題就會(huì)簡(jiǎn)單一百倍。但是這里簡(jiǎn)單了,給其他地方就帶來(lái)了災(zāi)難。就是說(shuō)線程阻塞前需要更新OopMap,如果不更新,沒(méi)有這個(gè)數(shù)據(jù)的話,GC時(shí)就需要掃描所有線程的所有棧的所有棧幀來(lái)查找根對(duì)象。
OopMap的存在,其實(shí)又是一種空間換時(shí)間的策略。因?yàn)橄啾葍?nèi)存的價(jià)格,降低GC延時(shí)明顯更重要。
但是JVM的執(zhí)行流那么多,何時(shí)?在什么地方?更新OopMap呢?這就是安全點(diǎn)存在的意義。安全點(diǎn)同時(shí)解決了STW及更新OopMap。
其實(shí)也可以這樣說(shuō),不理解安全點(diǎn)就無(wú)法理解STW,甚至于無(wú)法理解GC。
安全點(diǎn)
安全點(diǎn)涉及的知識(shí)點(diǎn)非常多、非常底層。本篇文章就講安全點(diǎn)中與STW相關(guān)的知識(shí)點(diǎn)。其他的知識(shí)點(diǎn)后面會(huì)寫(xiě)系列文章展開(kāi)講。感興趣的小伙伴可以關(guān)注我公眾號(hào)關(guān)注我的發(fā)文動(dòng)態(tài):硬核子牙。
這段代碼是大家看GC源碼時(shí)經(jīng)??吹降?/p>
SafepointSynchronize::begin
我把hotspot源碼中核心的代碼粘過(guò)來(lái)

這段代碼到底做了哪些事情呢:
告訴JVM馬上要開(kāi)始GC(下雨)了,開(kāi)始做準(zhǔn)備工作了(準(zhǔn)備收衣服了)。本質(zhì)就是修改一些屬性位。比如第5行代碼,通知解釋器做好準(zhǔn)備工作,迎接GC到來(lái)。
將polling_page對(duì)應(yīng)的物理頁(yè)設(shè)置成不可讀狀態(tài)。這步非常非常重要。等下說(shuō)。
不停檢測(cè),確定是否所有的線程都已進(jìn)入安全點(diǎn)。只有都已進(jìn)入安全點(diǎn),才能執(zhí)行GC邏輯。
STW的真面目
安全點(diǎn)是如何解決讓所有的線程都阻塞的呢?開(kāi)啟安全點(diǎn)為什么要將物理頁(yè)的屬性改為不可讀呢?
因?yàn)镴VM在生成執(zhí)行流代碼的時(shí)候,都會(huì)在適合作為安全點(diǎn)的地方插入一段代碼

這段代碼就是安全點(diǎn)的本質(zhì),也是觸發(fā)STW的本質(zhì)。什么意思呢?如果os::_polling_page對(duì)應(yīng)的物理頁(yè)屬性是可讀的,這段代碼并沒(méi)什么特殊意義。但是如果是不可讀的,讀的時(shí)候就會(huì)觸發(fā)段異常,對(duì)應(yīng)的操作系統(tǒng)信號(hào):SIGSEGV。
JVM捕獲了這個(gè)異常,并進(jìn)行了處理。所有的線程都是在這個(gè)地方STW的。

這就是安全點(diǎn)難的地方,涉及到的知識(shí)點(diǎn)太多太底層!其實(shí)我搞手寫(xiě)JVM小班的核心目的不是帶你寫(xiě)一個(gè)JVM,其一是讓你通過(guò)手寫(xiě)JVM了解hotspot的體系,你才能看得懂hotspot源碼。其二,也是最核心的,掌握底層。因?yàn)檎莆樟说讓樱銓?duì)技術(shù)就沒(méi)有恐懼之心了,你會(huì)覺(jué)得你無(wú)所不能。事實(shí)上,相對(duì)的無(wú)所不能是可以做到的,只是需要時(shí)間沉淀。啰嗦了兩句哈。
GC結(jié)束后喚醒所有阻塞的線程,小伙伴們應(yīng)該能想到是在哪里?如何喚醒的了吧

以上就是JVM中如何做到STW使程序暫停的詳細(xì)內(nèi)容,更多關(guān)于STW如何暫停程序的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring使用aspect注解切面不起作用的排查過(guò)程及解決
這篇文章主要介紹了spring使用aspect注解切面不起作用的排查過(guò)程及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
SpringBoot 整合 Netty 多端口監(jiān)聽(tīng)的操作方法
Netty提供異步的、基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用以快速開(kāi)發(fā)高性能、高可靠性的網(wǎng)絡(luò) IO 程序,是目前最流行的 NIO 框架,這篇文章主要介紹了SpringBoot 整和 Netty 并監(jiān)聽(tīng)多端口,需要的朋友可以參考下2023-10-10
ArrayList及HashMap的擴(kuò)容規(guī)則講解
今天小編就為大家分享一篇關(guān)于ArrayList及HashMap的擴(kuò)容規(guī)則講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02
淺談springboot項(xiàng)目中定時(shí)任務(wù)如何優(yōu)雅退出
這篇文章主要介紹了淺談springboot項(xiàng)目中定時(shí)任務(wù)如何優(yōu)雅退出?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
減小Maven項(xiàng)目生成的JAR包體積實(shí)現(xiàn)提升運(yùn)維效率
在Maven構(gòu)建Java項(xiàng)目過(guò)程中,減小JAR包體積可通過(guò)排除不必要的依賴和使依賴jar包獨(dú)立于應(yīng)用jar包來(lái)實(shí)現(xiàn),在pom.xml文件中使用<exclusions>標(biāo)簽排除不需要的依賴,有助于顯著降低JAR包大小,此外,將依賴打包到應(yīng)用外,可減少應(yīng)用包的體積2024-10-10
使用Jenkins來(lái)構(gòu)建SVN+Maven項(xiàng)目的實(shí)現(xiàn)
這篇文章主要介紹了使用Jenkins來(lái)構(gòu)建SVN+Maven項(xiàng)目的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

