Java中Stop-The-World機制簡稱STW,是在執行垃圾收集算法時,Java應用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫停現象,全局停頓,所有Java代碼停止,native代碼可以執行,但不能與JVM交互;這些現象多半是由于gc引起。
GC時的Stop the World(STW)是大家最大的敵人。但可能很多人還不清楚,除了GC,JVM下還會發生停頓現象。
JVM里有一條特殊的線程--VM Threads,專門用來執行一些特殊的VM Operation,比如分派GC,thread dump等,這些任務,都需要整個Heap,以及所有線程的狀態是靜止的,一致的才能進行。所以JVM引入了安全點(Safe Point)的概念,想辦法在需要進行VM Operation時,通知所有的線程進入一個靜止的安全點。
除了GC,其他觸發安全點的VM Operation包括:
1. JIT相關,比如Code deoptimization, Flushing code cache ;
2. Class redefinition (e.g. javaagent,AOP代碼植入的產生的instrumentation) ;
3. Biased lock revocation 取消偏向鎖 ;
4. Various debug operation (e.g. thread dump or deadlock check);
監控安全點看看JVM到底發生了什么?
最簡單的做法,在JVM啟動參數的GC參數里,多加一句:
-XX:+PrintGCApplicationStoppedTime
它就會把全部的JVM停頓時間(不只是GC),打印在GC日志里。
2016-08-22T00:19:49.559+0800: 219.140: Total time for which application threads were stopped: 0.0053630 seconds
這是個很有用的必配參數,可以打出幾乎一切的停頓……
但是,在JDK1.7.40以前的版本,它居然沒有打印時間戳,所以只能知道JVM停了多久,但不知道什么時候停的。此時一個土辦法就是加多一句“ -XX:+PrintGCApplicationConcurrentTime”,打印JVM在兩次停頓之間的正常運行時間(同樣沒有時間戳),但好歹能配合有時間戳的GC日志,反推出Stop發生的時間了。
2016-08-22T00:19:50.183+0800: 219.764: Application time: 5.6240430 seconds
如何打印出事哪種原因導致的停頓呢?
再多加兩個參數:-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1
此時,在stdout中會打出類似的內容
vmop [threads: total initially_running wait_to_block]1913.425: GenCollectForAllocation [ 55 2 0 ] [time: spin block sync cleanup vmop] page_trap_count[ 0 0 0 0 6 ] 0
此日志分兩段,第一段是時間戳,VM Operation的類型,以及線程概況
total: 安全點里的總線程數
initially_running: 安全點時開始時正在運行狀態的線程數
wait_to_block: 在VM Operation開始前需要等待其暫停的線程數
第二行是到達安全點時的各個階段以及執行操作所花的時間,其中最重要的是vmop
spin: 等待線程響應
safepoint號召的時間
block: 暫停所有線程所用的時間
sync: 等于 spin+block,這是從開始到進入安全點所耗的時間,可用于判斷進入安全點耗時
cleanup: 清理所用時間
vmop: 真正執行VM Operation的時間
可見,那些很多但又很短的安全點,全都是RevokeBias,詳見 偏向鎖實現原理, 高并發的應用一般會干脆在啟動參數里加一句"-XX:-UseBiasedLocking"取消掉它。另外還看到有些類型是no vm operation, 文檔上說是保證每秒都有一次進入安全點(如果這秒已經GC過就不用了),給一些需要在安全點里進行,又非緊急的操作使用,比如一些采樣型的Profiler工具,可用-DGuaranteedSafepointInterval來調整,不過實際看它并不是每秒都會發生,時間不定。
在實戰中,我們利用安全點日志,發現過有程序定時調用Thread Dump等等情況。不過因為安全點日志默認輸出到stdout,因為性能及stdout日志的整潔性等原因,我們平時默認沒有開啟它。只有在需要時才打開。
再再增加下面三個參數,可以知道更多VM里發生的事情。可惜JVM不會因為設了這三個參數,就把安全點日志轉移到vm.log里面來,而是白白打印了兩次。
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/dev/shm/vm.log
總結
本文關于快速理解Java垃圾回收和jvm中的stw的介紹就到這里,希望對大家有所幫助,有什么問題可以隨時留言,小編會及時回復大家的。
原文鏈接:http://blog.csdn.net/b_11111/article/details/52725494