-verbose:gc html
-XX:+PrintGCDetails java
-XX:+PrintGCDateStamps git
-Xloggc:/path/gc.log github
-XX:+PrintGC包含-verbose:gc 算法
-XX:+PrintGCDetails //包含-XX:+PrintGC 多線程
只要設置-XX:+PrintGCDetails 就會自動帶上-verbose:gc和-XX:+PrintGC 併發
-XX:+PrintGCDateStamps/-XX:+PrintGCTimeStamps 輸出gc的觸發時間 oracle
提示:gc日誌文件不會分割須要手動處理. app
2014-02-28T11:59:00.638+0800: 766.537:[GC2014-02-28T11:59:00.638+0800: 766.537: [ParNew: 1770882K->212916K(1835008K), 0.0834220 secs] 5240418K->3814487K(24903680K), 0.0837310 secs] [Times: user=1.12 sys=0.02, real=0.08 secs]
2014-02-28T11:59:00 …(時間戳):[GC(Young GC)(時間戳):[ParNew(使用ParNew做爲年輕代的垃圾回收期): jvm
1770882K(年輕代垃圾回收前的大小)->212916K(年輕代垃圾回收之後的大小)(1835008K)(年輕代的capacity), 0.0834220 secs(回收時間)]
5240418K(整個heap垃圾回收前的大小)->3814487K(整個heap垃圾回收後的大小)(24903680K)(heap的capacity), 0.0837310secs(回收時間)]
[Times: user=1.12(Young GC用戶耗時) sys=0.02(Young GC系統耗時), real=0.08 secs(Young GC實際耗時)]
其中 Young GC回收了1770882-212916=1557966K內存
Heap經過此次回收總共減小了 5240418-3814487=1425931 K的內存。1557966-1425931=132035K說明此次Young GC有約128M的內存被移動到了Old Gen,
提示:進代量(Young->Old)須要重點觀察,預防promotion failed.
2014-02-28T23:58:42.314+0800: 25789.661: [GC [1 CMS-initial-mark: 17303356K(23068672K)] 18642315K(24903680K), 1.0400410 secs] [Times: user=1.04 sys=0.00, real=1.04 secs] 2014-02-28T23:58:43.354+0800: 25790.701: [CMS-concurrent-mark-start] 2014-02-28T23:58:43.717+0800: 25791.064: [CMS-concurrent-mark: 0.315/0.363 secs] [Times: user=1.64 sys=0.02, real=0.37 secs] 2014-02-28T23:58:43.717+0800: 25791.064: [CMS-concurrent-preclean-start] 2014-02-28T23:58:43.907+0800: 25791.254: [CMS-concurrent-preclean: 0.181/0.190 secs] [Times: user=0.20 sys=0.01, real=0.19 secs] 2014-02-28T23:58:43.907+0800: 25791.254: [CMS-concurrent-abortable-preclean-start] CMS: abort preclean due to time 2014-02-28T23:58:49.082+0800: 25796.429: [CMS-concurrent-abortable-preclean: 5.165/5.174 secs] [Times: user=5.40 sys=0.04, real=5.17 secs] 2014-02-28T23:58:49.083+0800: 25796.430: [GC[YG occupancy: 1365142 K (1835008 K)]2014-02-28T23:58:49.083+0800: 25796.430: [Rescan (parallel) , 0.9690640 secs]2014-02-28T23:58:50.052+0800: 25797.399: [weak refs processing, 0.0006190 secs]2014-02-28T23:58:50.053+0800: 25797.400: [scrub string table, 0.0006290 secs] [1 CMS-remark: 17355150K(23068672K)] 18720292K(24903680K), 0.9706650 secs] [Times: user=16.49 sys=0.06, real=0.97 secs] 2014-02-28T23:58:50.054+0800: 25797.401: [CMS-concurrent-sweep-start] 2014-02-28T23:58:51.940+0800: 25799.287: [CMS-concurrent-sweep: 1.875/1.887 secs] [Times: user=2.03 sys=0.03, real=1.89 secs] 2014-02-28T23:58:51.941+0800: 25799.288: [CMS-concurrent-reset-start] 2014-02-28T23:58:52.067+0800: 25799.414: [CMS-concurrent-reset: 0.127/0.127 secs] [Times: user=0.13 sys=0.00, real=0.13 secs] 2014-03-01T00:00:36.293+0800: 25903.640: [GC2014-03-01T00:00:36.293+0800: 25903.640: [ParNew: 1805234K->226801K(1835008K), 0.1020510 secs] 10902912K->9434796K(24903680K), 0.1023150 secs] [Times: user=1.35 sys=0.02, real=0.10 secs] 2014-03-01T00:07:13.559+0800: 26300.906: [GC2014-03-01T00:07:13.559+0800: 26300.906: [ParNew: 1799665K->248991K(1835008K), 0.0876870 secs] 14086673K->12612462K(24903680K), 0.0879620 secs] [Times: user=1.24 sys=0.01, real=0.09 secs]
CMS的gc日誌分爲一下幾個步驟,重點關注initial-mark和remark這兩個階段,由於這兩個階段會stop進程。
初始標記(init mark):收集根引用,這是一個stop-the-world階段。
併發標記(concurrent mark):這個階段能夠和用戶應用併發進行。遍歷老年代的對象圖,標記出活着的對象。
併發預清理(concurrent preclean):這一樣是一個併發的階段。主要的用途也是用來標記,用來標記那些在前面標記以後,發生變化的引用。主要是爲了縮短remark階段的stop-the-world的時間。
從新標記(remark):這是一個stop-the-world的操做。暫停各個應用,統計那些在發生變化的標記。
併發清理(concurrent sweep):併發掃描整個老年代,回收一些在對象圖中不可達對象所佔用的空間。
併發重置(concurrent reset):重置某些數據結果,以備下一個回收週期
提示:紅色爲所有暫停階段重點關注.
[GC [1 CMS-initial-mark: 17303356K(23068672K)] 18642315K(24903680K), 1.0400410 secs] [Times: user=1.04 sys=0.00, real=1.04 secs]
其中數字依表示標記先後old區的全部對象佔內存大小和old的capacity,整個JavaHeap(不包括perm)全部對象佔內存總的大小和JavaHeap的capacity。
[GC[YG occupancy: 1365142 K (1835008 K)]2014-02-28T23:58:49.083+0800: 25796.430: [Rescan (parallel) , 0.9690640 secs]2014-02-28T23:58:50.052+0800: 25797.399: [weak refs processing, 0.0006190 secs]2014-02-28T23:58:50.053+0800: 25797.400: [scrub string table, 0.0006290 secs] [1 CMS-remark: 17355150K(23068672K)] 18720292K(24903680K), 0.9706650 secs] [Times: user=16.49 sys=0.06, real=0.97 secs]
Rescan (parallel)表示的是多線程處理young區和多線程掃描old+perm的總時間, parallel 表示多GC線程並行。
weak refs processing 處理old區的弱引用的總時間,用於回收native memory.等等
參考資料:
https://blogs.oracle.com/jonthecollector/entry/the_unspoken_cms_and_printgcdetails
https://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs
2014-03-03T09:38:26.457+0800: 233373.804: [GC [1 CMS-initial-mark: 17319615K(23068672K)] 17351070K(24903680K), 0.0419440 secs] [Times: user=0.04 sys=0.00, real=0.04 secs] 2014-03-03T09:38:26.499+0800: 233373.846: [CMS-concurrent-mark-start] 2014-03-03T09:38:28.175+0800: 233375.522: [GC2014-03-03T09:38:28.175+0800: 233375.522: [CMS2014-03-03T09:38:28.887+0800: 233376.234: [CMS-concurrent-mark: 1.989/2.388 secs] [Times: user=14.37 sys=0.24, real=2.39 secs] (concurrent mode failure): 17473174K->8394653K(23068672K), 19.3309170 secs] 18319691K->8394653K(24903680K), [CMS Perm : 23157K->23154K(98304K)], 19.3311700 secs] [Times: user=22.18 sys=0.00, real=19.33 secs]
concurrent mode failure通常發生在CMS GC 運行過程當中,老年代空間不足,引起MSC(Full GC)
上面的這條發日誌說明CMS運行到CMS-concurrent-mark過程當中就出現空間不足,產生併發失敗(17319615K(23068672K)佔77%),
解決思路:下降YGC頻率,下降CMS GC觸發時機,適當下降CMSInitiatingOccupancyFraction.
2014-02-27T21:19:42.460+0800: 210095.040: [GC 210095.040: [ParNew (promotion failed): 1887487K->1887488K(1887488K), 0.4818790 secs]210095.522: [CMS: 13706434K->7942818K(23068672K), 9.7152990 secs] 15358303K->7942818K(24956160K), [CMS Perm : 27424K->27373K(98304K)], 10.1974110 secs] [Times: user=12.06 sys=0.01, real=10.20 secs]
promotion failed通常發生在新生代晉升老年代時,老年代空間不夠或連續空間不夠卻還沒達到old區的觸發值,引起Full Gc.
解決思路:因爲heap碎片,YGC晉升對象過大,過長.(mid/long Time Object),調整-XX:PretenureSizeThreshold=65535,-XX:MaxTenuringThreshold=6
6:system.gc()產生的Full GC日誌
<strong>2014-01-21T17:44:01.554+0800: 50212.568: [Full GC (System) 50212.568: [CMS: 943772K220K(2596864K), 2.3424070 secs] 1477000K->220K(4061184K), [CMS Perm : 3361K->3361K(98304K)], 2.3425410 secs] [Times: user=2.33 sys=0.01, real=2.34 secs]</strong>
Full GC (System)意味着這是個system.gc調用產生的MSC。
「943772K->220K(2596864K), 2.3424070 secs」表示:此次MSC先後old區內總對象大小,old的capacity及此次MSC耗時。
「1477000K->220K(4061184K)」表示:此次MSC先後JavaHeap內總對象大小,JavaHeap的capacity。
「3361K->3361K(98304K)], 2.3425410 secs」表示:此次MSC先後Perm區內總對象大小,Perm區的capacity。
解決:
使用-XX:+DisableExplicitGC參數,System.gc()會變成空調用.
若是應用有地方大量使用direct memory 或 rmi,那麼使用-XX:+DisableExplicitGC要當心。
可使用-XX:+ExplicitGCInvokesConcurrent替換把 System.gc()從Full GC換成CMS GC.
緣由:
DirectByteBuffer沒有finalizer,native memory的清理工做是經過sun.misc.Cleaner自動完成
sun.misc.Cleaner是基於PhantomReference的清理工具,Full GC/Old GC會對old gen作reference processing,同時觸發Cleaner對已死的DirectByteBuffer對象作清理。
若是長時間沒有GC或者只作了young GC的話,不會觸發old區Cleaner的工做,容易產生DirectMemory OOM.
參考:https://gist.github.com/rednaxelafx/1614952
RMI會作的是分佈式GC。Sun JDK的分佈式GC是用純Java實現的,爲RMI服務。
參考:http://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html
2014-02-13T13:48:06.349+0800: 7.092: [GC 7.092: [ParNew: 471872K->471872K(471872K), 0.0000420 secs]7.092: [CMS: 366666K->524287K(524288K), 27.0023450 secs] 838538K->829914K(996160K), [CMS Perm : 3196K->3195K(131072K)], 27.0025170 secs]
ParNew的時間特別短,jvm在minor gc前會首先確認old是否是足夠大,若是不夠大,此次young gc直接返回,進行MSC(Full GC)。
jvm參數分固定參數和非固定參數
如:-Xmx,-Xms,-Xmn,-Xss.
如:
-XX:+<option> 啓用選項
-XX:-<option> 不啓用選項
-XX:<option>=<number> 給選項設置一個數字類型值,可跟單位,例如 128k, 2g
-XX:<option>=<string> 給選項設置一個字符串值,例如-XX:HeapDumpPath=./dump.log
打印出JVM初始化完畢後全部跟最初的默認值不一樣的參數及它們的值,jdk1.5後支持.
線上建議打開,能夠看到本身改了哪些值.
顯示全部可設置的參數及」參數處理」後的默認值。參數自己只從JDK6 U21後支持
但是查看不一樣版本默認值,以及是否設置成功.輸出的信息中」=」表示使用的是初始默認值,而」:=」表示使用的不是初始默認值
如:jdk6/7 -XX:+MaxTenuringThreshold 默認值都是15,可是在使用CMS收集器後,jdk6默認4 , jdk7默認6.
[hbase96 logs]# java -version java version "1.6.0_27-ea" [hbase96 logs]# java -XX:+PrintFlagsInitial | grep MaxTenuringThreshold intx MaxTenuringThreshold = 15 {product} [hbase96 logs]# java -XX:+PrintFlagsFinal -XX:+UseConcMarkSweepGC | grep MaxTenuringThreshold intx MaxTenuringThreshold := 4 {product} [zw-34-71 logs]# java -version java version "1.7.0_45" [zw-34-71 logs]# java -XX:+PrintFlagsInitial | grep MaxTenuringThreshold intx MaxTenuringThreshold = 15 {product} [zw-34-71 logs]# java -XX:+PrintFlagsFinal -XX:+UseConcMarkSweepGC | grep MaxTenuringThreshold intx MaxTenuringThreshold := 6 {product}
在」參數處理」以前全部可設置的參數及它們的值,而後直接退出程序.
這裏的」參數處理」指: 檢查參數之間是否有衝突,經過ergonomics調整某些參數的值等.
[hbase96 logs]# java -version java version "1.6.0_27-ea" [hbase96 logs]# java -XX:+PrintFlagsInitial | grep UseCompressedOops bool UseCompressedOops = false {lp64_product} [hbase96 logs]# java -XX:+PrintFlagsFinal | grep UseCompressedOops bool UseCompressedOops := true {lp64_product}
jdk6/7:
#java -server -XX:+UseConcMarkSweepGC -XX:+PrintFlagsFinal | grep -P "CMSInitiatingOccupancyFraction|CMSTriggerRatio|MinHeapFreeRatio" intx CMSInitiatingOccupancyFraction = -1 {product} intx CMSTriggerRatio = 80 {product} uintx MinHeapFreeRatio = 40 {product}
計算公式:
CMSInitiatingOccupancyFraction = (100 – MinHeapFreeRatio) + (CMSTriggerRatio * MinHeapFreeRatio / 100)
最終結果: 在jdk6/7中 CMSInitiatingOccupancyFraction默認值是92% .不是網上傳的68%; 都這麼傳,是由於 「深刻理解Java虛擬機」一書中是68%,但它用的是jdk5 , jdk5的CMSTriggerRatio默認值是20,坑爹…
一圖勝千言,直接上圖
物理分代是除G1以外的JVM 內存分配方式,jvm 經過-Xmx,-Xmn/newRatio等參數將jvm heap劃分紅物理固定大小,對於不一樣場景比例應該設置成多少很考驗經驗.
一篇JVM CMS優化講解的很是好的文章: how-tame-java-gc-pauses
邏輯分代是之後的趨勢(PS:jkd8連perm都不區分了。), 不須要使用者在糾結Xms/Xmn,SurvivorRatio等比例問題,採用動態算法調整分代大小。