快速理解Java垃圾回收和jvm中的stw
Java中Stop-The-World機(jī)制簡稱STW,是在執(zhí)行垃圾收集算法時,Java應(yīng)用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫?,F(xiàn)象,全局停頓,所有Java代碼停止,native代碼可以執(zhí)行,但不能與JVM交互;這些現(xiàn)象多半是由于gc引起。
GC時的Stop the World(STW)是大家最大的敵人。但可能很多人還不清楚,除了GC,JVM下還會發(fā)生停頓現(xiàn)象。
JVM里有一條特殊的線程--VM Threads,專門用來執(zhí)行一些特殊的VM Operation,比如分派GC,thread dump等,這些任務(wù),都需要整個Heap,以及所有線程的狀態(tài)是靜止的,一致的才能進(jìn)行。所以JVM引入了安全點(Safe Point)的概念,想辦法在需要進(jìn)行VM Operation時,通知所有的線程進(jìn)入一個靜止的安全點。
除了GC,其他觸發(fā)安全點的VM Operation包括:
1. JIT相關(guān),比如Code deoptimization, Flushing code cache ;
2. Class redefinition (e.g. javaagent,AOP代碼植入的產(chǎn)生的instrumentation) ;
3. Biased lock revocation 取消偏向鎖 ;
4. Various debug operation (e.g. thread dump or deadlock check);
監(jiān)控安全點看看JVM到底發(fā)生了什么?
最簡單的做法,在JVM啟動參數(shù)的GC參數(shù)里,多加一句:
-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
這是個很有用的必配參數(shù),可以打出幾乎一切的停頓……
但是,在JDK1.7.40以前的版本,它居然沒有打印時間戳,所以只能知道JVM停了多久,但不知道什么時候停的。此時一個土辦法就是加多一句“ -XX:+PrintGCApplicationConcurrentTime”,打印JVM在兩次停頓之間的正常運行時間(同樣沒有時間戳),但好歹能配合有時間戳的GC日志,反推出Stop發(fā)生的時間了。
2016-08-22T00:19:50.183+0800: 219.764: Application time: 5.6240430 seconds
如何打印出事哪種原因?qū)е碌耐nD呢?
再多加兩個參數(shù):-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1
此時,在stdout中會打出類似的內(nèi)容
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: 安全點里的總線程數(shù)
initially_running: 安全點時開始時正在運行狀態(tài)的線程數(shù)
wait_to_block: 在VM Operation開始前需要等待其暫停的線程數(shù)
第二行是到達(dá)安全點時的各個階段以及執(zhí)行操作所花的時間,其中最重要的是vmop
spin: 等待線程響應(yīng)
safepoint號召的時間
block: 暫停所有線程所用的時間
sync: 等于 spin+block,這是從開始到進(jìn)入安全點所耗的時間,可用于判斷進(jìn)入安全點耗時
cleanup: 清理所用時間
vmop: 真正執(zhí)行VM Operation的時間
可見,那些很多但又很短的安全點,全都是RevokeBias,詳見 偏向鎖實現(xiàn)原理, 高并發(fā)的應(yīng)用一般會干脆在啟動參數(shù)里加一句"-XX:-UseBiasedLocking"取消掉它。另外還看到有些類型是no vm operation, 文檔上說是保證每秒都有一次進(jìn)入安全點(如果這秒已經(jīng)GC過就不用了),給一些需要在安全點里進(jìn)行,又非緊急的操作使用,比如一些采樣型的Profiler工具,可用-DGuaranteedSafepointInterval來調(diào)整,不過實際看它并不是每秒都會發(fā)生,時間不定。
在實戰(zhàn)中,我們利用安全點日志,發(fā)現(xiàn)過有程序定時調(diào)用Thread Dump等等情況。不過因為安全點日志默認(rèn)輸出到stdout,因為性能及stdout日志的整潔性等原因,我們平時默認(rèn)沒有開啟它。只有在需要時才打開。
再再增加下面三個參數(shù),可以知道更多VM里發(fā)生的事情??上VM不會因為設(shè)了這三個參數(shù),就把安全點日志轉(zhuǎn)移到vm.log里面來,而是白白打印了兩次。
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/dev/shm/vm.log
總結(jié)
本文關(guān)于快速理解Java垃圾回收和jvm中的stw的介紹就到這里,希望對大家有所幫助,感興趣的朋友可以參閱:淺談Java回收對象的標(biāo)記和對象的二次標(biāo)記過程 、Java虛擬機(jī)裝載和初始化一個class類代碼解析 、Java中map遍歷方式的選擇問題詳解等,有什么問題可以隨時留言,小編會及時回復(fù)大家的。
相關(guān)文章
劍指Offer之Java算法習(xí)題精講二叉樹專項訓(xùn)練
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03spring boot項目打包成war在tomcat運行的全步驟
這篇文章主要給大家介紹了關(guān)于spring boot項目打包成war在tomcat運行的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04詳解SpringBoot和Mybatis配置多數(shù)據(jù)源
本篇文章主要介紹了詳解SpringBoot和Mybatis配置多數(shù)據(jù)源,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05SpringBoot ThreadLocal實現(xiàn)公共字段自動填充案例講解
每一次在Controller層中封裝改動數(shù)據(jù)的方法時都要重新設(shè)置一些共性字段,顯得十分冗余。為了解決此問題也是在項目中第一次利用到線程,總的來說還是讓我眼前一亮,也開闊了視野,對以后的開發(fā)具有深遠(yuǎn)的意義2022-10-10Spring Boot集成MyBatis實現(xiàn)通用Mapper的配置及使用
關(guān)于MyBatis,大部分人都很熟悉。MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。這篇文章主要介紹了Spring Boot集成MyBatis實現(xiàn)通用Mapper,需要的朋友可以參考下2018-08-08