這篇文章主要介紹了快速理解Java垃圾回收和jvm中的stw,涉及Java程式碼的停頓,jvm中的線程等相關內容,還是十分不錯的,需要的朋友可以參考。
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
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
##此日誌分兩段,第一段是時間戳,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的解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!