jvm系列(五):Java GC 分析
Java GC就是JVM記錄儀,書畫了JVM各個(gè)分區(qū)的表演。
什么是 Java GC
Java GC(Garbage Collection,垃圾收集,垃圾回收)機(jī)制,是Java與C++/C的主要區(qū)別之一,作為Java開發(fā)者,一般不需要專門編寫內(nèi)存回收和垃圾清理代碼,對內(nèi)存泄露和溢出的問題,也不需要像C程序員那樣戰(zhàn)戰(zhàn)兢兢。這是因?yàn)樵贘ava虛擬機(jī)中,存在自動(dòng)內(nèi)存管理和垃圾清掃機(jī)制。概括地說,該機(jī)制對JVM(Java Virtual Machine)中的內(nèi)存進(jìn)行標(biāo)記,并確定哪些內(nèi)存需要回收,根據(jù)一定的回收策略,自動(dòng)的回收內(nèi)存,永不停息(Nerver Stop)的保證JVM中的內(nèi)存空間,防止出現(xiàn)內(nèi)存泄露和溢出問題。
在Java語言出現(xiàn)之前,就有GC機(jī)制的存在,如Lisp語言),Java GC機(jī)制已經(jīng)日臻完善,幾乎可以自動(dòng)的為我們做絕大多數(shù)的事情。然而,如果我們從事較大型的應(yīng)用軟件開發(fā),曾經(jīng)出現(xiàn)過內(nèi)存優(yōu)化的需求,就必定要研究Java GC機(jī)制。
簡單總結(jié)一下,Java GC就是通過GC收集器回收不在存活的對象,保證JVM更加高效的運(yùn)轉(zhuǎn)。如果不了解GC算法和垃圾回收器可以參考這篇文章:jvm系列(三):GC算法 垃圾收集器。
如何獲取 Java GC日志
一般情況可以通過兩種方式來獲取GC日志,一種是使用命令動(dòng)態(tài)查看,一種是在容器中設(shè)置相關(guān)參數(shù)打印GC日志。
命令動(dòng)態(tài)查看
Java 自動(dòng)的工具行命令,jstat可以用來動(dòng)態(tài)監(jiān)控JVM內(nèi)存的使用,統(tǒng)計(jì)垃圾回收的各項(xiàng)信息。
比如常用命令, jstat-gc 統(tǒng)計(jì)垃圾回收堆的行為
- $ jstat -gc 1262
- S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
- 26112.0 24064.0 6562.5 0.0 564224.0 76274.5 434176.0 388518.3 524288.0 42724.7 320 6.417 1 0.398 6.815
也可以設(shè)置間隔固定時(shí)間來打?。?/p>
- $ jstat -gc 1262 2000 20
這個(gè)命令意思就是每隔2000ms輸出1262的gc情況,一共輸出20次
更詳細(xì)的內(nèi)容參考這篇文章:jvm系列(四):jvm調(diào)優(yōu)-命令篇
GC參數(shù)
JVM的GC日志的主要參數(shù)包括如下幾個(gè):
- -XX:+PrintGC 輸出GC日志
- -XX:+PrintGCDetails 輸出GC的詳細(xì)日志
- -XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以基準(zhǔn)時(shí)間的形式)
- -XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2017-09-04T21:53:59.234+0800)
- -XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息
- -Xloggc:../logs/gc.log 日志文件的輸出路徑
在生產(chǎn)環(huán)境中,根據(jù)需要配置相應(yīng)的參數(shù)來監(jiān)控JVM運(yùn)行情況。
Tomcat 設(shè)置示例
我們經(jīng)常在tomcat的啟動(dòng)參數(shù)中添加JVM相關(guān)參數(shù),這里有一個(gè)典型的示例:
- JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4
- -verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log
- -Djava.awt.headless=true
- -XX:+PrintGCTimeStamps -XX:+PrintGCDetails
- -Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000
- -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"
根據(jù)上面的參數(shù)我們來做一下解析:
-Xms2000m-Xmx2000m-Xmn800m-XX:PermSize=64m-XX:MaxPermSize=256m
Xms,即為jvm啟動(dòng)時(shí)得JVM初始堆大小,Xmx為jvm的***堆大小,xmn為新生代的大小,permsize為***代的初始大小,MaxPermSize為***代的***空間。
-XX:SurvivorRatio=4
SurvivorRatio為新生代空間中的Eden區(qū)和救助空間Survivor區(qū)的大小比值,默認(rèn)是32,也就是說Eden區(qū)是 Survivor區(qū)的32倍大小,要注意Survivo是有兩個(gè)區(qū)的,因此Surivivor其實(shí)占整個(gè)young genertation的1/34。調(diào)小這個(gè)參數(shù)將增大survivor區(qū),讓對象盡量在survitor區(qū)呆長一點(diǎn),減少進(jìn)入年老代的對象。去掉救助空間的想法是讓大部分不能馬上回收的數(shù)據(jù)盡快進(jìn)入年老代,加快年老代的回收頻率,減少年老代暴漲的可能性,這個(gè)是通過將-XX:SurvivorRatio 設(shè)置成比較大的值(比如65536)來做到。
-verbose:gc-Xloggc:$CATALINA_HOME/logs/gc.log
將虛擬機(jī)每次垃圾回收的信息寫到日志文件中,文件名由file指定,文件格式是平文件,內(nèi)容和-verbose:gc輸出內(nèi)容相同。
-Djava.awt.headless=true Headless模式是系統(tǒng)的一種配置模式。在該模式下,系統(tǒng)缺少了顯示設(shè)備、鍵盤或鼠標(biāo)。
-XX:+PrintGCTimeStamps-XX:+PrintGCDetails
設(shè)置gc日志的格式
-Dsun.rmi.dgc.server.gcInterval=600000-Dsun.rmi.dgc.client.gcInterval=600000
指定rmi調(diào)用時(shí)gc的時(shí)間間隔
-XX:+UseConcMarkSweepGC-XX:MaxTenuringThreshold=15 采用并發(fā)gc方式,經(jīng)過15次minor gc 后進(jìn)入年老代
如何分析GC日志
摘錄GC日志一部分
Young GC回收日志:
- 2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K->10738K(274944K)] 371093K->147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs]
Full GC回收日志:
- 2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K->0K(274944K)] [ParOldGen: 136447K->140379K(302592K)] 147186K->140379K(577536K) [PSPermGen: 85411K->85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]
通過上面日志分析得出,PSYoungGen、ParOldGen、PSPermGen屬于Parallel收集器。其中PSYoungGen表示gc回收前后年輕代的內(nèi)存變化;ParOldGen表示gc回收前后老年代的內(nèi)存變化;PSPermGen表示gc回收前后***區(qū)的內(nèi)存變化。young gc 主要是針對年輕代進(jìn)行內(nèi)存回收比較頻繁,耗時(shí)短;full gc 會對整個(gè)堆內(nèi)存進(jìn)行回城,耗時(shí)長,因此一般盡量減少full gc的次數(shù)
通過兩張圖非常明顯看出gc日志構(gòu)成:
Young GC日志:
Full GC日志:
GC分析工具
GChisto
GChisto是一款專業(yè)分析gc日志的工具,可以通過gc日志來分析:Minor GC、full gc的時(shí)間、頻率等等,通過列表、報(bào)表、圖表等不同的形式來反應(yīng)gc的情況。雖然界面略顯粗糙,但是功能還是不錯(cuò)的。
配置好本地的jdk環(huán)境之后,雙擊GChisto.jar,在彈出的輸入框中點(diǎn)擊 add 選擇gc.log日志
GC Pause Stats:可以查看GC 的次數(shù)、GC的時(shí)間、GC的開銷、***GC時(shí)間和最小GC時(shí)間等,以及相應(yīng)的柱狀圖
GC Pause Distribution:查看GC停頓的詳細(xì)分布,x軸表示垃圾收集停頓時(shí)間,y軸表示是停頓次數(shù)。
GC Timeline:顯示整個(gè)時(shí)間線上的垃圾收集
不過這款工具已經(jīng)不再維護(hù)
GC Easy
這是一個(gè)web工具,在線使用非常方便.
地址: http://gceasy.io
進(jìn)入官網(wǎng),講打包好的zip或者gz為后綴的壓縮包上傳,過一會就會拿到分析結(jié)果。
推薦使用此工具進(jìn)行g(shù)c分析。
【本文為51CTO專欄作者“純潔的微笑”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系作者獲取授權(quán)】