全稱“Java Virtual Machine statistics monitoring tool”(statistics 統計;monitoring 監控;tool 工具)
用於監控虛擬機的各種運行狀態信息的命令行工具。
可以查看虛擬機中進程的類加載,內存,垃圾回收、jit編譯等運行數據。
jstat 命令格式: jstat [-option] [vmid] [int s|ms] [count]
例如: jstat -class 64363 1s 10
簡單解釋: -class 是option的選項參數,要看類加載信息;64363是es的pid 1s 就是間隔一秒執行一次,10 就是執行10次
後面的執行時間和執行次數可以不寫,那就默認執行一次。
可以看下面的-class選項的說明中的這個命令的執行效果圖。
《深入理解Java虛擬機》上面弄的截圖。
一眼望去,關於gc的選項很多,也說明實際現場出問題差不多都跟gc的STW時間太久導致程序間歇性死亡假死或者直接gg。比如es要是gc時間久了,就完蛋了。
下面分別看看,順便親自手動試試每個option命令(在jdk 1.8 的環境下測試的截圖)
1, -class 監視類裝載、卸載數量,總空間、類裝載所耗費時間
具體例子:jstat -class 64363 1s 10
- Loaded:加載class的數量 Number of classes loaded.
- Bytes: Number of kBs loaded.
- Unloaded:卸載class數量(這個unloaded 翻譯成未加載呢?我覺得不合適吧)
- Bytes: Number of Kbytes unloaded.
- Time:Time spent performing class loading and unloading operations. 執行 類加載和卸載操作所花費的時間
查看es進程的類加載信息,es的pid是64363 ,間隔1s執行一次,一共執行10次。
elasticsearch的運行要加載一萬兩千多個類呢,還有unloaded 類。
這不是未加載的意思。
2,-compiler 輸出jit編譯器編譯過的方法耗時等信息
jstat -compiler 64363
- Compiled:執行的編譯任務數量。Number of compilation tasks performed.
- Failed:失敗數量
- Invalid:不可用數量
- Time:時間
- FailedType:失敗類型
- FailedMethod:失敗的方法
還是使用es的進程來搞實驗,編譯的數量是2萬多,但是load的class數量才一萬多,爲什麼?
我這麼解釋:把整個項目都給編譯一遍,但是並不是所有的類都會被jvm加載。這麼解釋還湊合吧。
3,-printcompilation 輸出已經被jit編譯的方法
jstat -printcompilation 629756
額,我也不知道這個jit是幹啥的,就擺個截圖放這吧,這個不是es而是另一個消費kafka的進程的pid。
4,-gc 監視Java堆狀況,eden,2個s區,old,元空間等容量,gc時間等情況
jstat -gc 64363 1s 100
看es進程的gc情況,一秒一刷執行100次,執行一次,遇不到gc
以下幾個容量大小的單位都是 kb,包括後面的幾個option的截圖,裏面容量的單位都是 kb
- S0C:第一個倖存區的大小(S0 Capacity)
- S1C:第二個倖存區的大小(S1 Capacity)
- S0U:第一個倖存區的使用大小(S0 Used / utilization 還是used單詞簡單)
- S1U:第二個倖存區的使用大小(S1 Used)
- EC:伊甸園區的大小(Eden Capacity 伊甸園 亞當夏娃造人的公園,不造的科普一下。)
- EU:伊甸園區的使用大小(Eden Used)
- OC:老年代大小(Old Capacity)
- OU:老年代使用大小(Old Used)
- MC:元空間大小(Metaspace Capacity 已經不是之前叫的method area了,現在改名叫元空間了,雖然都是M開頭的)
- MU:元空間使用大小(Metaspace Used)
- CCSC:壓縮類空間大小 (Compressed class space capacity (kB).)
- CCSU:壓縮類空間使用大小(Compressed class space used (kB).)
- YGC:年輕代垃圾回收次數(young gc)
- YGCT:年輕代垃圾回收消耗時間(young gc time)
- FGC:對堆內存整體包含新生代,老年代,永久代)進行垃圾回收次數(full gc)
- FGCT:對堆內存整體包含新生代,老年代,永久代)進行垃圾回收消耗時間(full gc time)
- GCT:垃圾回收消耗總時間(gc time)
一直在看的elasticsearch的進程的一些參數設置的截圖,使用的命令:jps -vm |grep elastic
從上面的gc的圖,可以看出不少理論:
1,2個s區,但是一直有個s區的used是0.0,是空白的。
2,2個s區大小是一致的
3,上面截圖中出現一次young gc(0.0換列的那個地方),YGC 次數由10703次變成10704次,加1,young gc之前,eden區都快滿了538926.4 / 545344 = 98.8%了,gc之後,s1被完全回收,eden區的空間被回收大部分,s0區被安排了些新生的數據對象,old used 由529563.2變成了529706.2,增加了一點點,說明有部分對象被安排到了老年代去了。後面的gc time肯定不是某一次的gc時間,而是從啓動到現在的總時間,從圖中看到沒有發生gc之前,這個值是一直不變的,gc之後,稍微長大了一丟丟。算一下,一次young gc的時間是0.011秒,full gc 沒有在打印期間觸發,後面的整個gc 時間增加也就0.01秒。啓動2天的es的full gc的次數136,整個full gc的時間也就8秒多。啓動之後整個程序的所有gc時間400多秒。
4,young gc 的次數比full gc的次數少的多,一個是1.1萬次,一個是100多次。
(full難道不是整個堆內存嗎?爲啥有的人說full gc是對old區進行gc呢?我反對。所以,我上面寫的就是對整個堆內存gc)
5,-gccapacity 與-gc基本相同,主要關注Java堆各區域使用到的最大最小空間
jstat -gccapacity 64363 1s 100
- NGCMN:新生代最小容量 (New Generation Capacity Min)
- NGCMX:新生代最大容量(New Generation Capacity Max)
- NGC:當前新生代容量(New Generation Capacity)
- S0C:第一個倖存區大小(S0 Capacity)
- S1C:第二個倖存區的大小(S1 Capacity)
- EC:伊甸園區的大小(Eden Capacity 伊甸園 亞當夏娃造人的公園,不造的科普一下。)
- OGCMN:老年代最小容量(Old Generation Capacity Min)
- OGCMX:老年代最大容量(Old Generation Capacity Min)
- OGC:當前老年代大小(Old Generation Capacity)
- OC:當前老年代大小(Old Capacity)
- MCMN:最小元數據容量(Metasapce Capacity Min)
- MCMX:最大元數據容量(Metasapce Capacity Max)
- MC:當前元數據空間大小(Metasapce Capacity)
- CCSMN:最小壓縮類空間大小
- CCSMX:最大壓縮類空間大小
- CCSC:當前壓縮類空間大小
- YGC:年輕代gc次數(young gc)
- FGC:對堆內存整體包含新生代,老年代,永久代)GC次數 (full gc)
Java內存的差不多每個分區都有相應的配置來設置這個區域的最大值和最小值,在實際分配空間的時候,不夠的時候會自動擴展,直到達到此區域的最大值,還無法滿足程序在內存分配空間的時候,纔會報OOM異常。想一下jvm裏面幾個分區的OOM情況。
在上面的實際圖中,年輕代,老年代的最大最小設置的一樣的,所以這2個分區的大小就是固定的,另外2個元空間和壓縮類空間最小值是0,那大小會動態變化的就是後面這2個分區,以及young gc和full gc的次數了。截圖中並沒有發生young gc。
6,-gcutil 與-gc基本,主要關注已使用空間佔此空間的百分比
jstat -gcutil 64363 1s 100
- S0:倖存1區當前使用比例
- S1:倖存2區當前使用比例
- E:伊甸園區使用比例
- O:老年代使用比例
- M:元數據區使用比例
- CCS:壓縮使用比例
- YGC:年輕代垃圾回收次數
- YGCT:年輕代垃圾回的總時間
- FGC:對堆內存整體包含新生代,老年代,永久代)垃圾回收次數
- FGCT:對堆內存整體包含新生代,老年代,永久代)垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
截圖裏面發生了一次young gc,2個s區一個被清空,eden區的使用率99.75變成9.6之後,一路往上漲,最終又觸發下一次young gc
old區百分比比較穩定,說明堆裏面的對象基本都在這個eden區出生,在新生代中,大部分對象都幹完事兒就被和諧了,內存使用正常,要是代碼中有會造成內存溢出的代碼,那麼這個old區的百分比,每次young gc之後,就會漲,直到OOM,或者不OOM,但是卡在快滿的情況下。
7,-gccause 與-gcutil一樣,多2列輸出導致上次gc的原因
jstat -gccause 64363 1s 100
- LGCC:上次gc的原因(last gc cause)
- GCT:Total garbage collection time.(gc cause)
還是差不多,eden區,使用百分比一路上升到百分百的時候,對象沒地方分配空間了,就觸發young gc,上次gc的原因,就是 Allocation Failure 分配空間失敗。
垃圾回收還會有其它原因嗎?
比如,我們通過代碼顯示調用System.gc(),是不是可以手動的告訴jvm gc一下,還有不少其它的方法,我也不知道。。。
8,-gcnew 統計新生代的gc情況
jstat -gcnew 64363 1s 100
- S0C:第一個倖存區大小
- S1C:第二個倖存區的大小
- S0U:第一個倖存區的使用大小
- S1U:第二個倖存區的使用大小
- TT:對象在新生代存活的次數 (Tenuring threshold.)
- MTT:對象在新生代存活的最大次數(Maximum tenuring threshold.)
- DSS:期望的倖存區大小(Desired survivor size (kB).)
- EC:伊甸園區的大小
- EU:伊甸園區的使用大小
- YGC:年輕代垃圾回收次數
- YGCT:年輕代垃圾回收消耗時間
這些新參數TT MTT DSS 估計和jvm的新生代的設計有關係了,暫時看不出門道來。
上圖發生來young gc,時間大概0.003秒
9, -gcnewcapacity 類似 -gcnew,關係new區的各個最大和最新空間
jstat -gcnewcapacity 64363 1s 100
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:當前新生代容量
- S0CMX:最大幸存1區大小
- S0C:當前倖存1區大小
- S1CMX:最大幸存2區大小
- S1C:當前倖存2區大小
- ECMX:最大伊甸園區大小
- EC:當前伊甸園區大小
- YGC:年輕代垃圾回收次數
- FGC:對堆內存整體包含新生代,老年代,永久代)回收次數
上面看到新生的最大最小設置一樣,幾個區的容量都是定值,不帶變化的。
新生代大小 = s0 + s1 + eden = new區
上面截圖中發生了gc的,但是gc跟new區的幾個子分區的容量是不會有關係的。
10,-gcold 統計old區,堆裏面老年代的gc情況
jstat -gcold 64363 1s 100
- MC:元空間大小
- MU:元空間使用大小
- CCSC:壓縮類空間大小
- CCSU:壓縮類空間使用大小
- OC:老年代大小
- OU:老年代使用大小
- YGC:年輕代垃圾回收次數
- FGC:對堆內存整體包含新生代,老年代,永久代)垃圾回收次數
- FGCT:對堆內存整體包含新生代,老年代,永久代)垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
最終沒被回收的對象都在堆的老年代裏面,看老年代的已經使用的大小,再考慮考慮自己代碼裏面不回收的對象的大小,會不會把這個地方佔滿,會不會佔這麼大的空間。可以大致目測一下對象個數。推測這個區的佔用是否合理,來判斷代碼是不是內存泄露了。不過,這個太難了,堆裏面又不是隻分你的對象,還有不少其它jar包自帶的
11,-gcoldcapacity 統計old區的各個分區的容量最大最小情況
jstat -gcoldcapacity 64363 1s 100
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:當前老年代大小
- OC:老年代大小
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
好像也沒啥,就是看看各個區的大小,這個截圖裏面old區的最大最小當前實際都是一個值。
12,-gcpermcapacity 被 -gcmetacapacity 替代,看元空間的gc情況
jstat -gcmetacapacity 64363 1s 100
- MCMN: 最小元數據容量
- MCMX:最大元數據容量
- MC:當前元數據空間大小
- CCSMN:最小壓縮類空間大小
- CCSMX:最大壓縮類空間大小
- CCSC:當前壓縮類空間大小
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
他當時寫那本書的時候,還在jdk1.6呢,在1.8之後jvm中內存分區有變化了,方法區變成了元空間。
當時說方法區的gc回收效果並不可觀,沒有堆的gc那麼可觀,一次gc回收 80%的空間。
估計一般gc都是主要看堆,看堆的 new 和old,重點都在old區。