JVM问题排查思路


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

0YV6te.png

  • 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);
        }
    }
}

0Nr7es.png

从上图中可以看到byte[]占用9462402字节≈9.02MB,在尝试继续分配时失败

元数据空间溢出


  TOC