一、常用命令
jps -l 查看 Java 进程的 PID
jinfo -flags <pid> 查看 JVM 启动时的具体参数
jcmd <pid> VM.flags 查看 JVM 启动时的具体参数(比 jinfo 更常用)
jcmd <PID> GC.class_histogram -all | tail -n 10 查看存活对象统计(-all 参数表示只统计当前存活的对象),输出结果的尾行第一个数字是当前堆中存活的对象总个数,第二个数字是当前实际存活对象的总大小,单位是字节(Byte)。
jstat -gc <PID> | awk '{print "老年代实际存活: " $8/1024 " MB"}'
jcmd <PID> GC.run 手动触发一次 Full GC
docker stast 用于实时查看 Docker 容器的资源使用情况,查看具体服务使用 docker stats <CONTAINER_ID>
jcmd <pid> GC.heap_info 查看堆配置和当前堆使用情况
jcmd <pid> VM.native_memory summary 查看 JVM 总内存构成,排查 OOMKilled、内存泄漏等问题
jmap -histo:live <pid> 专门用来查看当前 JVM 堆内存中所有存活对象的直方图(Histogram)
jstat -gc <PID> | awk '{print ($3+$4+$6+$8)/1024 " MB"}' 大概的看一眼堆内存使用大小
堆外内存估算方法:
以下是生产环境中最核心的启动参数与 jcmd VM.flags 输出的精确一一对应表格,以及它们在输出中的实际长相:
| 常用启动参数 | jcmd 对应的 -XX: 变量名 | 单位与含义说明 |
|---|---|---|
-Xms |
InitialHeapSize |
初始堆大小(字节)。例如 InitialHeapSize=2147483648 (2G) |
-Xmx |
MaxHeapSize |
最大堆大小(字节)。例如 MaxHeapSize=4294967296 (4G) |
-Xmn |
NewSize / MaxNewSize |
新生代大小。-Xmn 会同时将这两个变量设为相同的值 |
-Xss |
ThreadStackSize |
每个线程的栈大小(注意:单位通常是 KB)。例如 ThreadStackSize=1024 代表 1MB |
-XX:MetaspaceSize |
MetaspaceSize |
元空间触发 Full GC 的初始阈值(字节) |
-XX:MaxMetaspaceSize |
MaxMetaspaceSize |
元空间允许的最大大小(字节) |
-XX:MaxDirectMemorySize |
MaxDirectMemorySize |
最大堆外直接内存大小(字节,默认为 0 表示由 JVM 自动决定) |
-XX:SurvivorRatio |
SurvivorRatio |
Eden 区与单个 Survivor 区的比例(默认 8,即占 $\frac{8}{10}$) |
-XX:+UseG1GC |
UseG1GC=true |
代表当前应用正在使用 G1 垃圾回收器 |
-XX:+HeapDumpOnOutOfMemoryError |
HeapDumpOnOutOfMemoryError=true |
确认 OOM 时自动导出堆快照功能已开启 |
-XX:HeapDumpPath |
HeapDumpPath |
后面会直接接字符串路径,如 HeapDumpPath=/logs |
jcmd <pid> VM.flags 默认只打印被修改过的、非默认的参数。如果你在输出里找不到 ThreadStackSize 或 MaxDirectMemorySize,说明你在启动时根本没有配它,它目前正在使用 JVM 的默认值。如果你想连同默认值一起看,彻底对齐所有参数,请使用这个进阶命令:jcmd <pid> VM.flags -all。它会把 700 多个内部变量全部列出。你可以通过 | grep InitialHeapSize 或者是 MaxRAMPercentage 来精准狙击你想核对的任何隐藏指标。
查看堆外内存使用率,最有用的是开使用 Native Memory Tracking(NMT)
- 启动参数:
-XX:NativeMemoryTracking=summary,或者更详细:-XX:NativeMemoryTracking=detail - 检查是否开启:
jcmd <pid> VM.native_memory - 查看汇总:
jcmd <pid> VM.native_memory summary - 查看输出结果
差值对比诊断(最强排查技巧):
- 刚启动或运行正常时,设定基线:
jcmd 1 VM.native_memory baseline - 运行一段时间后或内存开始暴涨时,查看增长差值:
jcmd 1 VM.native_memory summary
ParalleGC 参数建议配置:
-XX:+UseParallelGC |
根据 JVM 性能调优圣经,为了让 Parallel GC 达到吞吐量最大化,各代大小应满足:
- 老年代(Old Gen)配置 = 活跃数据的 2 ~ 3 倍。
- 年轻代(Young Gen)配置 = 活跃数据的 1 ~ 1.5 倍。
- 总堆内存(Xmx / Xms) = 活跃数据的 3 ~ 4.5 倍。
活跃数据可以手动进行一次 GC 之后查看:jcmd <pid> VM.run 或者 jmap -histo:live <pid>
举个例子:通过 jstat 或 GC 日志发现,Full GC 后老年代还剩 600M 数据(这就是活跃数据)。
- 老年代分配:$600\text{M} \times 2 = 1200\text{M}$
- 年轻代分配:$600\text{M} \times 1.5 = 900\text{M}$
- 最终堆大小:$1200\text{M} + 900\text{M} = 2100\text{M}$(约 2G)。如果容器是 4G,这证明 2G~2.5G 的堆对 Parallel 来说极其宽裕。
对象晋升过程:
```Eden
↓ GC
S0(age=1)
↓ GC
S1(age=2)
↓ GC
S0(age=3)
↓ GC
S1(age=4)
达到阈值:-XX:MaxTenuringThreshold=15,或者 Survivor 放不下,晋升到 Old。


