1. 程式人生 > >Java分析系列之三:jstat命令的使用及VM Thread分析

Java分析系列之三:jstat命令的使用及VM Thread分析

前面提到了一個使用jstack的shell指令碼,通過命令可以很快地定位到指定執行緒對應的堆疊資訊。

目錄 [隱藏]

使用jstat命令

當伺服器CPU100%的時候,通過定位佔用資源最大的執行緒定位到 VM Thread

"VM Thread" prio=10 tid=0x00007fbea80d3800 nid=0x5e9 runnable

這個時候需要使用 jstat -gc <pid> <period> <times>

命令檢視gc的資訊,顯示結果如下:

S0C    S1C    S0U    S1U      EC       EU      OC         OU       PC        PU       YGC     YGCT    FGC   FGCT       GCT
64.0   64.0   0.0    0.0   332992.0   0.0    666304.0   73192.5   83968.0   83967.9   6893   17.576  6882   2705.923  2723.499

結果中每個專案的含義可以參考官方對jstat的文件,簡單翻譯如下:
- S0C: Young Generation第一個survivor space的記憶體大小 (kB).
- S1C: Young Generation第二個survivor space的記憶體大小 (kB).
- S0U: Young Generation第一個Survivor space當前已使用的記憶體大小 (kB).
- S1U: Young Generation第二個Survivor space當前已經使用的記憶體大小 (kB).
- EC: Young Generation中eden space的記憶體大小 (kB).
- EU: Young Generation中Eden space當前已使用的記憶體大小 (kB).
- OC: Old Generation的記憶體大小 (kB).
- OU: Old Generation當前已使用的記憶體大小 (kB).
- PC: Permanent Generation的記憶體大小 (kB)
- PU: Permanent Generation當前已使用的記憶體大小 (kB).
- YGC: 從啟動到取樣時Young Generation GC的次數
- YGCT: 從啟動到取樣時Young Generation GC所用的時間 (s).
- FGC: 從啟動到取樣時Old Generation GC的次數.
- FGCT: 從啟動到取樣時Old Generation GC所用的時間 (s).
- GCT: 從啟動到取樣時GC所用的總時間 (s).

JDK8的結果稍微有所不同,結果含義可以參考:http://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

JVM記憶體模型

上面中的Young Generation、Permanent Generation和Old Generation等概念有一些混亂,這裡簡要的進行說明。簡單來說,JVM記憶體由堆(Heap)和非堆(Non-heap)記憶體組成,前者共執行在JVM之上的程式使用,後者供JVM自己使用。

堆記憶體的組成如下:

非堆記憶體由 Permanent Generation 和 Code Cache 兩部分組成:

  • Permanent Generation(持久代): 儲存虛擬機器自己的靜態(refective)資料,主要存放載入的Class類級別靜態物件如class本身,method,field等等。permanent generation空間不足會引發full GC;
  • Code Cache: 用於編譯和儲存原生代碼(native code)的記憶體,JVM內部處理或優化。

JVM記憶體引數設定

堆記憶體設定

  • 堆記憶體(總的)由 -Xms-Xmx 分別設定最小和最大堆記憶體
  • New Generation 由 -Xmn 設定,-XX:SurvivorRatio=m 設定 Eden和 兩個Survivor區的大小比值;-XX:NewRatio=n 設定 New Generation 和 Old Generation 的大小比值。
  • 每個執行緒的堆疊大小由 ·-Xss· 設定,JDK5.0以後每個執行緒堆疊大小為1M,以前每個執行緒堆疊大小為256K。在相同實體記憶體下,減小這個值能生成更多的執行緒。但是作業系統對一個程序內的執行緒數還是有限制的,不能無限生成,經驗值在3000~5000左右。

非堆記憶體設定

非堆記憶體由 -XX:PermSize=n-XX:MaxPermSize=n 分別設定最小和最大非堆記憶體大小

日誌分析

介紹完上面的概念之後,我們再來看最上面的日誌資訊,有兩個地方有問題:
一是FGC(完全GC)的數量太大了,正常來說FGC應該佔整個GC(YGC+FGC)的1%到5%才正常,上面日誌上完全GC的次數太多了;二是日誌中PU的值太大了,基本上已經達到設定的PC了,因此需要增大MaxPermSize的值。
不過這只是權宜之計,出現這麼大的非堆記憶體,肯定什麼地方出現了問題,還需要進一步找到佔用記憶體的原因,這也是後面文章所要說的。

參考資料:
100% CPU diagnosis
JVM調優總結 + jstat 分析
JVM調優總結(這個總結得比較全面)
JVM調優總結系列文章
JVM系列一:JVM記憶體組成及分配

記憶體洩漏