JVM问题排查思路
GC log
启动脚本
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+PrintGCApplicationStoppedTime -XX:+PrintTenuringDistribution
-Xloggc:/tmp/logs/gc_%p.log -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/logs -XX:ErrorFile=/tmp/logs/hs_error_pid%p.log
-XX:-OmitStackTraceInFastThrow
时间日志
time ls
-
real
real表示实际花费的时间,从开始到结束包括阻塞时间 -
user
user表示用户态说花费的时间,只统计本进程(多核状态)下所使用的时间 -
sys
sys表示的是进程在cpu核心状态下所使用的时间
jstat
# 垃圾回收信息
jstat -gcutil $pid 1000
# GC相关的信息
jstat -gc
### 输出
1. 命令格式:
jstat -gc <options> <vmid> <interval> <count>
<options>: 通常是 -gc,指定监控 GC 信息。
<vmid>: JVM 虚拟机的 ID。可以使用 jps 命令来查找。
<interval>: 采样间隔(以毫秒为单位)。
<count>: 采样次数。如果省略,则持续采样。
例子:<B>jstat -gc 14572 5000 100</B>
2. 输出结果字段详解:
以下是一个典型的 jstat -gc 输出示例,以及每个字段的详细解释:
```TXT
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 1024.0 8192.0 5120.0 20480.0 10240.0 256.0 128.0 32.0 16.0 10 0.500 2 0.200 0.700
S0C (Survivor 0 Capacity): Survivor 0 区的容量 (KB)。
S1C (Survivor 1 Capacity): Survivor 1 区的容量 (KB)。
S0U (Survivor 0 Utilization): Survivor 0 区已使用空间 (KB)。
S1U (Survivor 1 Utilization): Survivor 1 区已使用空间 (KB)。
EC (Eden Capacity): Eden 区的容量 (KB)。
EU (Eden Utilization): Eden 区已使用空间 (KB)。
OC (Old Capacity): 老年代的容量 (KB)。
OU (Old Utilization): 老年代已使用空间 (KB)。
MC (Metaspace Capacity): 元空间的容量 (KB)。 (JDK 8 使用 Metaspace 代替 PermGen)
MU (Metaspace Utilization): 元空间已使用空间 (KB)。
CCSC (Compressed Class Space Capacity): 压缩类空间容量 (KB)。
CCSU (Compressed Class Space Utilization): 压缩类空间已使用空间 (KB)。
YGC (Young Generation GC Count): 年轻代 GC 次数。
YGCT (Young Generation GC Time): 年轻代 GC 耗时 (秒)。
FGC (Full GC Count): Full GC 次数。
FGCT (Full GC Time): Full GC 耗时 (秒)。
GCT (Total GC Time): GC 总耗时 (秒)。
显示各个代的容量
jstat -gccapacity
显示classLoader
jstat -class
## 实际案例
### 老年代溢出
- Oomtest.java
```java
public class OldOomTest {
public static final int _1MB = 1024 * 1024;
/**
* 静态变量
*/
private static List<byte[]> bytes = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
while (true) {
byte[] bts = new byte[_1MB];
bytes.add(bts);
TimeUnit.SECONDS.sleep(1L);
}
}
}
从上图中可以看到byte[]占用9462402字节≈9.02MB,在尝试继续分配时失败