Skip to content

JVM 调优

调优基础

性能监控工具

bash
# JPS - 查看 Java 进程
jps -l
jps -v | grep heap

# JSTAT - 监控 JVM 统计信息
jstat -gcutil <pid> 1000 10   # 每秒一次,共10次
jstat -gc <pid>                # 详细 GC 信息

# JMAP - 导出堆转储
jmap -dump:format=b,file=heap.hprof <pid>
jmap -heap <pid>               # 堆配置和使用

# JSTACK - 打印线程堆栈
jstack <pid> > thread.log

# JINFO - 查看/修改配置
jinfo -flags <pid>            # 查看所有参数
jinfo -flag MaxHeapSize <pid> # 查看某个参数

常用监控命令

bash
# GC 统计
jstat -gcutil 12345 1000

# 输出示例:
# S0     S1     E      O      M     YGC     YGCT    FGC    FGCT     GCT
# 0.00  65.00  55.00  45.00  91.00    125    0.456     3    0.125    0.581

# S0/S1 = Survivor 区使用率
# E = Eden 区使用率
# O = Old 区使用率
# M = Metaspace 使用率
# YGC = Young GC 次数
# YGCT = Young GC 总耗时(秒)
# FGC = Full GC 次数
# FGCT = Full GC 总耗时(秒)

JVM 参数

常用参数

bash
# 堆内存
-Xms256m          # 初始堆大小
-Xmx512m          # 最大堆大小
-Xmn128m          # 新生代大小
-Xss1m            # 线程栈大小
-XX:MetaspaceSize=256m    # 元空间初始大小
-XX:MaxMetaspaceSize=512m # 元空间最大

# 新生代
-XX:NewRatio=2           # 老年代/新生代比例 (默认2)
-XX:SurvivorRatio=8      # Eden/Survivor比例 (默认8)

# GC
-XX:+UseG1GC             # 使用 G1 收集器
-XX:MaxGCPauseMillis=200 # 最大 GC 停顿时间
-XX:+PrintGCDetails      # 打印 GC 详情
-XX:+PrintGCDateStamps   # 打印 GC 时间戳
-Xloggc:/path/to/gc.log  # GC 日志文件

# OOM 处理
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump

JDK 8 推荐配置

bash
# 通用服务器配置
java -server \
  -Xms4g -Xmx4g \
  -Xmn2g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/var/log/heap.hprof \
  -Xloggc:/var/log/gc.log \
  -jar app.jar

调优场景

场景1:Young GC 频繁

症状

  • YGC 次数很多
  • YGCT 累积增长快

原因

  • Eden 区太小
  • 对象分配过快

解决

bash
# 方案1:增大 Eden 区
-Xmn512m -XX:SurvivorRatio=6

# 方案2:直接增大新生代
-Xmn1g

场景2:Full GC 频繁

症状

  • Full GC 次数多
  • FGCT 累积增长快

原因

  • 老年代空间不足
  • 内存泄漏
  • 大对象直接进入老年代

解决

bash
# 方案1:检查内存泄漏
jmap -histo <pid> | head -30  # 查看对象分布

# 方案2:调整大对象阈值
-XX:PretenureSizeThreshold=2m  # 超过2m直接进老年代

# 方案3:增大老年代
-Xms4g -Xmx4g -Xmn1g  # 老年代 3g

场景3:GC 停顿时间过长

症状

  • 用户请求响应慢
  • GC 日志显示 STW 时间长

原因

  • 堆太大
  • G1 Region 太多

解决

bash
# 方案1:减小堆大小(并行 GC 场景)
-Xms2g -Xmx2g

# 方案2:调整 G1 参数
-XX:MaxGCPauseMillis=100      # 目标停顿时间
-XX:G1HeapRegionSize=16m     # Region 大小
-XX:ConcGCThreads=4          # 并发 GC 线程数

OOM 问题排查

步骤

┌─────────────────────────────────────────────────────────────────┐
│                      OOM 排查流程                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   1. 配置 JVM 参数保留堆 dump                                    │
│      -XX:+HeapDumpOnOutOfMemoryError                            │
│      -XX:HeapDumpPath=/path/to/dump.hprof                       │
│                                                                  │
│   2. 重现问题,生成 dump 文件                                    │
│                                                                  │
│   3. 使用 MAT 分析 dump                                          │
│      - Histogram: 按对象数量/大小排序                            │
│      - Dominator Tree: 对象引用关系                              │
│      - Top Consumers: 最大的对象                                │
│                                                                  │
│   4. 定位问题代码                                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

MAT 使用

bash
# 启动 MAT
mat64.sh heap.hprof

# 常见分析视图:
# - Histogram: 按类统计对象
# - Dominator Tree: 支配树,找 GC Root 引用链
# - Top Consumers: 内存消耗最大的对象/类
# - Leak Suspects: 可疑的内存泄漏

常见 OOM 原因

OOM 类型原因解决方案
Java heap space对象太多增大堆,检查内存泄漏
GC overhead limitGC 太频繁减少对象创建,优化代码
Metaspace类太多增大元空间,检查 CGLib
Direct bufferNIO 直接内存限制大小
Unable to create native thread线程太多减少线程数

Arthas 工具

常用命令

bash
# 启动 Arthas
java -jar arthas-boot.jar

# 监控方法调用
watch com.example.UserService getUser "{params, returnObj}"

# 查看方法耗时
trace com.example.UserService getUser

# 查看线程状态
thread

# 查看加载的类
sc com.example.*

# 反编译类
jad com.example.UserService

总结

JVM 调优核心知识点

知识点面试频率实战重要性
JVM 监控工具⭐⭐⭐⭐⭐⭐⭐⭐⭐
JVM 参数配置⭐⭐⭐⭐⭐⭐⭐⭐⭐
GC 日志分析⭐⭐⭐⭐⭐⭐⭐⭐⭐
OOM 排查⭐⭐⭐⭐⭐⭐⭐⭐⭐

⚠️ 易错点提醒

  1. 不是所有问题都需要调优,先用工具定位问题
  2. G1 不是万能的,小内存用 CMS,大内存用 G1
  3. 线上环境不要用 -Xms == -Xmx(固定大小更好)
  4. 内存泄漏排查用 MAT,循环依赖用 MAT Dominator Tree
  5. GC 日志是排查 GC 问题的第一手资料