safepoint是什麼
java程式裡面有很多很多的java線程,每個java線程又有自己的stack,并且共享了heap。這些線程一直運作呀運作,不斷對stack和heap進行操作。
這個時候如果JVM需要對stack和heap做一些操作該怎麼辦呢?
比如JVM要進行GC操作,或者要做heap dump等等,這時候如果線程都在對stack或者heap進行修改,那麼将不是一個穩定的狀态。GC直接在這種情況下操作stack或者heap,會導緻線程的異常。
怎麼處理呢?
這個時候safepoint就出場了。
safepoint就是一個安全點,所有的線程執行到安全點的時候就會去檢查是否需要執行safepoint操作,如果需要執行,那麼所有的線程都将會等待,直到所有的線程進入safepoint。
然後JVM執行相應的操作之後,所有的線程再恢複執行。
safepoint的例子
我們舉個例子,一般safepoint比如容易出現在循環周遊的情況,還是使用我們之前做null測試用的例子:
public class TestNull {
public static void main(String[] args) throws InterruptedException {
List<String> list= new ArrayList();
list.add("www.flydean.com");
for (int i = 0; i < 10000; i++)
{
testMethod(list);
}
Thread.sleep(1000);
}
private static void testMethod(List<String> list)
{
list.get(0);
}
}
運作結果如下:

标紅的就是傳說中的safepoint。
線程什麼時候會進入safepoint
那麼線程什麼時候會進入safepoint呢?
一般來說,如果線程在競争鎖被阻塞,IO被阻塞,或者在等待獲得螢幕鎖狀态時,線程就處于safepoint狀态。
如果線程再執行JNI代碼的哪一個時刻,java線程也處于safepoint狀态。因為java線程在執行本地代碼之前,需要儲存堆棧的狀态,讓後再移交給native方法。
如果java的位元組碼正在執行,那麼我們不能判斷該線程是不是在safepint上。
safepoint是怎麼工作的
如果你使用的是hotspot JVM,那麼這個safepoint是一個全局的safepoint,也就是說執行Safepoint需要暫停所有的線程。
如果你使用的是Zing,那麼可以線上程級别使用safepoint。
我們可以看到生成的彙編語言中safepoint其實是一個test指令。
test指向的是一個特殊的記憶體頁面位址,當JVM需要所有的線程都執行到safepint的時候,就會對該頁面做一個标記。進而通知所有的線程。
我們再用一張圖來詳細說明:
thread1在收到設定safepoint之前是一直執行的,在收到信号之後還會執行一段時間,然後到達Safepint暫停執行。
thread2先執行了一段時間,然後因為CPU被搶奪,空閑了一段時間,在這段時間裡面,thread2收到了設定safepoint的信号,然後thread2獲得執行權力,接着繼續執行,最後到達safepoint。
thread3是一個native方法,将會一直執行,知道safepoint結束。
thread4也是一個native方法,它和thread3的差別就在于,thread4在safepoint開始和結束之間結束了,需要将控制器轉交給普通的java線程,因為這個時候JVM在執行Safepoint的操作,是以任然需要暫停執行。
在HotSpot VM中,你可以在彙編語言中看到safepoint的兩種形式:'{poll}' 或者 '{poll return}' 。
總結
本文詳細的講解了JVM中Safepoint的作用,希望大家能夠喜歡。
本文作者:flydean程式那些事
本文連結:
http://www.flydean.com/jvm-safepoint2/本文來源:flydean的部落格
歡迎關注我的公衆号:程式那些事,更多精彩等着您!