快速理解Java垃圾回收和jvm中的stw
Java中Stop-The-World機(jī)制簡(jiǎn)稱STW,是在執(zhí)行垃圾收集算法時(shí),Java應(yīng)用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫?,F(xiàn)象,全局停頓,所有Java代碼停止,native代碼可以執(zhí)行,但不能與JVM交互;這些現(xiàn)象多半是由于gc引起。
GC時(shí)的Stop the World(STW)是大家最大的敵人。但可能很多人還不清楚,除了GC,JVM下還會(huì)發(fā)生停頓現(xiàn)象。
JVM里有一條特殊的線程--VM Threads,專門用來執(zhí)行一些特殊的VM Operation,比如分派GC,thread dump等,這些任務(wù),都需要整個(gè)Heap,以及所有線程的狀態(tài)是靜止的,一致的才能進(jìn)行。所以JVM引入了安全點(diǎn)(Safe Point)的概念,想辦法在需要進(jìn)行VM Operation時(shí),通知所有的線程進(jìn)入一個(gè)靜止的安全點(diǎn)。
除了GC,其他觸發(fā)安全點(diǎn)的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)控安全點(diǎn)看看JVM到底發(fā)生了什么?
最簡(jiǎn)單的做法,在JVM啟動(dòng)參數(shù)的GC參數(shù)里,多加一句:
-XX:+PrintGCApplicationStoppedTime
它就會(huì)把全部的JVM停頓時(shí)間(不只是GC),打印在GC日志里。
2016-08-22T00:19:49.559+0800: 219.140: Total time for which application threads were stopped: 0.0053630 seconds
這是個(gè)很有用的必配參數(shù),可以打出幾乎一切的停頓……
但是,在JDK1.7.40以前的版本,它居然沒有打印時(shí)間戳,所以只能知道JVM停了多久,但不知道什么時(shí)候停的。此時(shí)一個(gè)土辦法就是加多一句“ -XX:+PrintGCApplicationConcurrentTime”,打印JVM在兩次停頓之間的正常運(yùn)行時(shí)間(同樣沒有時(shí)間戳),但好歹能配合有時(shí)間戳的GC日志,反推出Stop發(fā)生的時(shí)間了。
2016-08-22T00:19:50.183+0800: 219.764: Application time: 5.6240430 seconds
如何打印出事哪種原因?qū)е碌耐nD呢?
再多加兩個(gè)參數(shù):-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1
此時(shí),在stdout中會(huì)打出類似的內(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
此日志分兩段,第一段是時(shí)間戳,VM Operation的類型,以及線程概況
total: 安全點(diǎn)里的總線程數(shù)
initially_running: 安全點(diǎn)時(shí)開始時(shí)正在運(yùn)行狀態(tài)的線程數(shù)
wait_to_block: 在VM Operation開始前需要等待其暫停的線程數(shù)
第二行是到達(dá)安全點(diǎn)時(shí)的各個(gè)階段以及執(zhí)行操作所花的時(shí)間,其中最重要的是vmop
spin: 等待線程響應(yīng)
safepoint號(hào)召的時(shí)間
block: 暫停所有線程所用的時(shí)間
sync: 等于 spin+block,這是從開始到進(jìn)入安全點(diǎn)所耗的時(shí)間,可用于判斷進(jìn)入安全點(diǎn)耗時(shí)
cleanup: 清理所用時(shí)間
vmop: 真正執(zhí)行VM Operation的時(shí)間
可見,那些很多但又很短的安全點(diǎn),全都是RevokeBias,詳見 偏向鎖實(shí)現(xiàn)原理, 高并發(fā)的應(yīng)用一般會(huì)干脆在啟動(dòng)參數(shù)里加一句"-XX:-UseBiasedLocking"取消掉它。另外還看到有些類型是no vm operation, 文檔上說是保證每秒都有一次進(jìn)入安全點(diǎn)(如果這秒已經(jīng)GC過就不用了),給一些需要在安全點(diǎn)里進(jìn)行,又非緊急的操作使用,比如一些采樣型的Profiler工具,可用-DGuaranteedSafepointInterval來調(diào)整,不過實(shí)際看它并不是每秒都會(huì)發(fā)生,時(shí)間不定。
在實(shí)戰(zhàn)中,我們利用安全點(diǎn)日志,發(fā)現(xiàn)過有程序定時(shí)調(diào)用Thread Dump等等情況。不過因?yàn)榘踩c(diǎn)日志默認(rèn)輸出到stdout,因?yàn)樾阅芗皊tdout日志的整潔性等原因,我們平時(shí)默認(rèn)沒有開啟它。只有在需要時(shí)才打開。
再再增加下面三個(gè)參數(shù),可以知道更多VM里發(fā)生的事情??上VM不會(huì)因?yàn)樵O(shè)了這三個(gè)參數(shù),就把安全點(diǎn)日志轉(zhuǎn)移到vm.log里面來,而是白白打印了兩次。
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/dev/shm/vm.log
總結(jié)
本文關(guān)于快速理解Java垃圾回收和jvm中的stw的介紹就到這里,希望對(duì)大家有所幫助,感興趣的朋友可以參閱:淺談Java回收對(duì)象的標(biāo)記和對(duì)象的二次標(biāo)記過程 、Java虛擬機(jī)裝載和初始化一個(gè)class類代碼解析 、Java中map遍歷方式的選擇問題詳解等,有什么問題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家的。
相關(guān)文章
談?wù)勎覍?duì)Spring Bean 生命周期的理解
Spring Bean 的生命周期在整個(gè) Spring 中占有很重要的位置,掌握這些可以加深對(duì) Spring 的理解。這篇文章主要介紹了Spring Bean 生命周期,需要的朋友可以參考下2018-03-03
Mybatis-Plus中and()和or()的使用與原理詳解
最近發(fā)現(xiàn)MyBatisPlus還是挺好用的,下面這篇文章主要給大家介紹了關(guān)于Mybatis-Plus中and()和or()的使用與原理的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
Spring Boot 3.x 集成 Eureka Server/Cl
隨著SpringBoot 3.x版本的開發(fā)嘗試,本文記錄了在集成Eureka Server/Client時(shí)所遇到的問題和解決方案,文中詳細(xì)介紹了搭建服務(wù)、配置文件和測(cè)試步驟,感興趣的朋友跟隨小編一起看看吧2024-09-09
舉例分析Python中設(shè)計(jì)模式之外觀模式的運(yùn)用
這篇文章主要介紹了Python中設(shè)計(jì)模式之外觀模式的運(yùn)用,外觀模式主張以分多模塊進(jìn)行代碼管理而減少耦合,需要的朋友可以參考下2016-03-03
如何實(shí)現(xiàn)Java的ArrayList經(jīng)典實(shí)體類
ArrayList是Java集合框架中一個(gè)經(jīng)典的實(shí)現(xiàn)類。他比起常用的數(shù)組而言,明顯的優(yōu)點(diǎn)在于,可以隨意的添加和刪除元素而不需考慮數(shù)組的大小。下面跟著小編一起來看下吧2017-02-02
Java通用BouncyCastle實(shí)現(xiàn)的DES3加密的方法
這篇文章主要介紹了Java通用BouncyCastle實(shí)現(xiàn)的DES3加密的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Springboot連接數(shù)據(jù)庫(kù)及查詢數(shù)據(jù)完整流程
今天給大家?guī)淼氖顷P(guān)于Springboot的相關(guān)知識(shí),文章圍繞著Springboot連接數(shù)據(jù)庫(kù)及查詢數(shù)據(jù)完整流程展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Spring?Boot監(jiān)控SQL運(yùn)行情況的全過程
這篇文章主要給大家介紹了關(guān)于Spring?Boot監(jiān)控SQL運(yùn)行情況的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02
JAVA設(shè)計(jì)模式之備忘錄模式原理與用法詳解
這篇文章主要介紹了JAVA設(shè)計(jì)模式之備忘錄模式,簡(jiǎn)單說明了備忘錄模式的概念、原理并結(jié)合實(shí)例形式分析了java備忘錄模式的具體定義及使用方法,需要的朋友可以參考下2017-08-08

