一文掌握J(rèn)VM?Safe?Point
大家好,我是樹哥。
關(guān)于 Safe Point 是 JVM 中很關(guān)鍵的一個概念,但我估計有不少同學(xué)不是很懂。于是今天跟大家來深入聊聊 Safe Point,希望通過這篇文章能解答這樣幾個問題:
什么是 Safe Point?為啥需要 Safe Point?Safe Point 與 Stop the World 的關(guān)系?
什么是 Safe Point
正如 Safe Point 名稱的寓意一樣,Safe Point 是一個線程可以安全停留在這里的代碼點。當(dāng)我們需要進行 GC 操作的時候,JVM 可以讓所有線程在 Safe Point 處停留下來,等到所有線程都停在 Safe Point 處時,就可以進行內(nèi)存引用分析,從而確定哪些對象是存活的、哪些對象是不存活的。
為什么讓大家更加場景化地理解 Safe Point 這個概念,可以設(shè)想如下場景:
當(dāng)需要 GC 時,需要知道哪些對象還被使用,或者已經(jīng)不被使用可以回收了,這樣就需要每個線程的對象使用情況。對于偏向鎖(Biased Lock),在高并發(fā)時想要解除偏置,需要線程狀態(tài)還有獲取鎖的線程的精確信息。對方法進行即時編譯優(yōu)化(OSR 棧上替換),或者反優(yōu)化(bailout 棧上反優(yōu)化),這需要線程究竟運行到方法的哪里的信息。
對于上面這些操作,都需要知道現(xiàn)場的各種信息,例如寄存器有什么內(nèi)容,堆使用情況等等。在做這些操作的時候,線程需要暫停,等到這些操作完成才行,否則會有并發(fā)問題,這就需要 Safe Point 的存在。
因此,我們可以將 Safe Point 理解成代碼執(zhí)行過程中的一些特殊位置,當(dāng)線程執(zhí)行到這個位置時,線程可以暫停。 Safe Point 處保存了其他位置沒有的一些當(dāng)前線程信息,可以提供給其他線程讀取,這些信息包括:線程上下文信息,對象的內(nèi)部指針等。
而 Stop the World 就是所有線程同時進入 Safe Point 并停留在那里,等待 JVM 進行內(nèi)存分析掃描,接著進行內(nèi)存垃圾回收的時間。
為啥需要 Safe Point
前面我們說到,Safe Point 其實就是一個代碼的特殊位置,在這個位置時線程可以暫停下來。而當(dāng)我們進行 GC 的時候,所有線程都要進入到 Safe Point 處,才可以進行內(nèi)存的分析及垃圾回收。根據(jù)這個過程,其實我們可以看到:Safe Point 其實就是柵欄的作用,讓所有線程停下來,否則如果所有線程都在運行的話,JVM 無法進行對象引用的分析,那么也無法進行垃圾回收了。
此外,另一個重要的 Java 線程特性 —— interrupted 也是根據(jù) Safe Point 實現(xiàn)的。當(dāng)我們在代碼里寫入 Thread.interrupt()
時,只有線程運行到 Safe Point 處時才知道是否發(fā)生了 interrupted。因此,Safe Point 也承擔(dān)了存儲線程通信的功能。
總結(jié)
簡單地說,Safe Point 就是人為規(guī)定出的一些代碼位置,在這些位置上線程可以暫停下來,從而讓 JVM 可以進行內(nèi)存對象引用分析等操作。此外,Safe Point 處也會存儲一些特殊的信息,從而支持 Java 的某些特性,例如:Java 的 interrupt 特性需要到 Safe Point 處才能知道。
其實關(guān)于 Safe Point 的內(nèi)容還有不少,例如:
什么地方會放 Safe Point?Safe Point 具體是怎么實現(xiàn)的?什么情況會讓所有線程進入 Safe Point?
但對于大多數(shù)應(yīng)用開發(fā)人員來說,其實暫時不需要了解得這么深,只需要知道啥是 Safe Point 以及其存在的價值即可。如果你對這些問題感興趣,可以通過參考資料部分詳細(xì)了解。
參考資料
JVM 相關(guān) - SafePoint 與 Stop The World 全解
JVM垃圾回收安全點Safe Point
GC安全點(Safepoint)
- 程序執(zhí)行時并非在所有地方都能停頓下來開始GC,只有在特定的位置才能停頓下來開始GC,這些位置稱為“安全點(Safepoint) ”
- Safe Point的選擇很重要,如果太少可能導(dǎo)致GC等待的時間太長,如果太頻繁可能導(dǎo)致運行時的性能問題。大部分指令的執(zhí)行時間都非常短暫,通常會根據(jù)“是否具有讓程序長時間執(zhí)行的特征”為標(biāo)準(zhǔn)。比如:選擇些執(zhí)行時間較長的指令作為Safe Point, 如方法調(diào)用、循環(huán)跳轉(zhuǎn)和異常跳轉(zhuǎn)等。
如何在GC發(fā)生時,檢查所有線程都跑到最近的安全點停頓下來呢?
- 搶先式中斷: (目前沒有虛擬機采用了) 首先中斷所有線程。如果還有線程不在安全點,就恢復(fù)線程,讓線程跑到安全點。
- 主動式中斷: 設(shè)置一個中斷標(biāo)志,各個線程運行到Safe Point的時候主動輪詢這個標(biāo)志,如果中斷標(biāo)志為真,則將自己進行中斷掛起。
安全區(qū)域(Safe Region)
Safepoint機制保證了程序執(zhí)行時,在不太長的時間內(nèi)就會遇到可進入GC的Safepoint
但是,程序“不執(zhí)行”的時候呢?例如線程處于Sleep 狀態(tài)或Blocked狀態(tài),這時候線程無法響應(yīng)JVM的中斷請求,“走” 到安全點去中斷掛起,JVM也不太可能等待線程被喚醒。對于這種情況,就需要安全區(qū)域(Safe Region)來解決。
安全區(qū)域是指在一段代碼片段中,對象的引用關(guān)系不會發(fā)生變化,在這個區(qū)域中的任何位置開始GC都是安全的。我們也可以把Safe Region 看做是被擴展了的Safepoint。
程序?qū)嶋H執(zhí)行時:
- 1、當(dāng)用戶線程運行到Safe Region的代碼時,首先標(biāo)識已經(jīng)進入了Safe Region,如果這段時間內(nèi)發(fā)生GC,JVM會忽略標(biāo)識為Safe Region狀態(tài)的用戶線程即用戶線程STW,等待JVM執(zhí)行GC完畢;
- 2、當(dāng)用戶線程即將離開Safe Region時, 會檢查JVM是否已經(jīng)完成GC,如果完成了,則用戶線程繼續(xù)運行,否則用戶線程必須等待直到收到可以安全離開SafeRegion的信號為止;
到此這篇關(guān)于一文講清楚 JVM Safe Point的文章就介紹到這了,更多相關(guān)JVM Safe Point內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問
本篇文章主要介紹了詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問,非常具有實用價值,有興趣的可以了解一下2017-09-09Jmeter的接口測試詳細(xì)步驟并實現(xiàn)業(yè)務(wù)閉環(huán)
這篇文章主要介紹了Jmeter的接口測試詳細(xì)步驟并實現(xiàn)業(yè)務(wù)閉環(huán),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08Spring?Boot?整合JPA?數(shù)據(jù)模型關(guān)聯(lián)使用操作(一對一、一對多、多對多)
這篇文章主要介紹了Spring?Boot?整合JPA?數(shù)據(jù)模型關(guān)聯(lián)操作(一對一、一對多、多對多),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07