當 Java 程序有性能問題時,尤其是響應時間有突然變化時,最好第一時間查看 GC 的狀態。一般用 jstat -gcutil <pid> 1s 來查看,那么它的輸出又是什么含義呢?

輸出樣例

一般會用兩種方式調用 jstat,一種看百分比,一種看具體數值(KB)。

例如 jstat -gcutil <pid> 1s 會每隔一秒輸出內存相關信息,示例輸出如下:

S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
0.00 0.00 34.47 44.29 93.05 83.49 10 0.036 2 0.117 0.153
0.00 0.00 45.70 44.29 93.05 83.49 10 0.036 2 0.117 0.153
0.00 0.00 58.12 44.29 93.05 83.49 10 0.036 2 0.117 0.153

 jstat -gc <pid> 1s 會輸出具體占用的數值,如下(比較長):

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU      YGC     YGCT    FGC    FGCT     GCT
4608.0 6656.0 0.0 0.0 62464.0 48011.4 30720.0 13605.8 35456.0 32991.3 10 0.036 2 0.117 0.153
4608.0 6656.0 0.0 0.0 62464.0 49261.5 30720.0 13605.8 35456.0 32991.3 10 0.036 2 0.117 0.153
4608.0 6656.0 0.0 0.0 62464.0 49261.5 30720.0 13605.8 35456.0 32991.3 10 0.036 2 0.117 0.153

要理解上面輸出的具體含義,需要了解 Java 的內存與 GC 的過程。

GC 過程簡要梳理

下圖是 GC 過程的概要(圖片來源 plumbr.io):

how-java-garbage-collection-works

如上圖,JVM 中的內存中的各個區域和作用如下(這里只是概述,細節麻煩查閱相關材料):

  • Eden(伊甸園):創建新對象時會從中分配內存。內存不足時,觸發 Young GC。不再被引用的對象將被拋棄,還被引用的對象會被復制到 Survivor 區。
  • Survivor(幸存者):有兩個 Survivor 區,GC 時會來回地把內存從其中一個區復制到另一個,交替進行。這里存儲的是一些“年輕”的對象,多次 GC (默認 15 次)后這些對象還停留在 Survivor 區,則認為它們會被長期引用,Survivor 空間不足時會將它們移動到“老生代”中。來回復制的過程中除了釋放內存,還起到整理內存碎片的作用。
  • Tenured(終生代)、也稱 Old Generation(老生代):保留那些“長期”被引用的對象。因此該區域只在 Full GC 的時候才會被整理。
  • PermGen/MetaSpace,Java 8 前是 PermGen,Java 8 后改成 MetaSpace。用來存儲諸如加載的類、字符串常量等元信息,與 GC 無關。

另外:Eden 與 Survivor 統稱“年輕代”,它們引發的 GC 也稱 “Young GC”。Young GC 通常比 Full GC 快很多,如果系統有卡頓,一般需要關注 Full GC。

jstat 輸出含義

了解了 GC 的過程,其實 jstat 的輸出通過查文檔 man jstat 就可以找到。這里權且作個翻譯:

-gcutil 的輸出如下

Column Description
S0 第 0 個 survivor(幸存區)使用的百分比
S1 第 1 個 survivor(幸存區)使用的百分比
E Eden 區使用內存的百分比
O 老生代內存使用的百分比
P/M PermGen/MetaSpace 的內存使用百分比
YGC 程序啟動以來 Young GC 發生的次數
YGCT 程序啟動以來 Young GC 共消耗的時間(s)
FGC 程序啟動以來 Full GC 發生的次數
FGCT 程序啟動以來 Full GC 共消耗的時間(s)
GCT 程序啟動以來 GC 的總用時(s)

-gc 的輸出如下

Column Description
SOC 第 0 個 Survivor 區的總空間 (KB).
S1C 第 1 個 Survivor 區的總空間 (KB).
S0U 第 0 個 Survivor 區已使用的空間 (KB).
S1U 第 1 個 Survivor 區已使用的空間 (KB).
EC Eden 區的總空間 (KB).
EU Eden 區已使用的空間 (KB).
OC OldGen 的總空間 (KB).
OU OldGen 已使用的空間 (KB).
PC/MC PermGen/MetaSpace 的總空間 (KB).
PU/MU PermGen/MetaSpace 使用的空間 (KB).
YGC 程序啟動以來 Young GC 發生的次數
YGCT 程序啟動以來 Young GC 共消耗的時間(s)
FGC 程序啟動以來 Full GC 發生的次數
FGCT 程序啟動以來 Full GC 共消耗的時間(s)
GCT 程序啟動以來 GC 的總用時(s)