Skip to content

性能调优

JVM参数

常用JVM参数?

答案:

堆内存设置

bash
-Xms2g          # 初始堆大小
-Xmx2g          # 最大堆大小(建议与Xms相同)
-Xmn1g          # 新生代大小
-Xss256k        # 栈大小
-XX:MetaspaceSize=128m      # 元空间初始大小
-XX:MaxMetaspaceSize=256m   # 元空间最大大小

垃圾收集器

bash
-XX:+UseG1GC                # 使用G1收集器
-XX:MaxGCPauseMillis=200    # 最大停顿时间
-XX:ParallelGCThreads=8     # 并行GC线程数
-XX:ConcGCThreads=2         # 并发GC线程数

GC日志

bash
-XX:+PrintGCDetails         # 打印GC详情
-XX:+PrintGCDateStamps      # 打印GC时间戳
-Xloggc:gc.log              # GC日志文件

OOM处理

bash
-XX:+HeapDumpOnOutOfMemoryError     # OOM时生成堆转储
-XX:HeapDumpPath=/tmp/heapdump.hprof
-XX:OnOutOfMemoryError="sh ~/restart.sh"  # OOM时执行脚本

性能监控

bash
-XX:+PrintFlagsFinal        # 打印所有JVM参数
-XX:+UnlockDiagnosticVMOptions  # 解锁诊断参数

性能分析工具

常用的性能分析工具?

答案:

1. jps - 查看Java进程

bash
jps -l  # 显示完整类名
jps -v  # 显示JVM参数

2. jstat - 查看JVM统计信息

bash
jstat -gc 12345 1000 10  # 每秒输出GC信息,共10次
jstat -gcutil 12345      # GC统计百分比
jstat -gccause 12345     # GC原因

3. jmap - 生成堆转储

bash
jmap -heap 12345         # 查看堆信息
jmap -histo 12345        # 查看对象统计
jmap -dump:format=b,file=heap.hprof 12345  # 生成堆转储

4. jstack - 查看线程堆栈

bash
jstack 12345             # 查看线程堆栈
jstack -l 12345          # 查看锁信息

5. jinfo - 查看和修改JVM参数

bash
jinfo -flags 12345       # 查看JVM参数
jinfo -flag MaxHeapSize 12345  # 查看具体参数

6. VisualVM

  • 图形化监控工具
  • 监控CPU、内存、线程
  • 生成和分析堆转储

7. JProfiler

  • 商业性能分析工具
  • CPU分析、内存分析、线程分析

8. Arthas

  • 阿里开源的Java诊断工具
  • 在线诊断,无需重启
bash
# 启动Arthas
java -jar arthas-boot.jar

# 常用命令
dashboard   # 仪表盘
thread      # 线程信息
jvm         # JVM信息
memory      # 内存信息
gc          # GC信息

性能调优

如何进行JVM调优?

答案:

1. 确定目标

  • 降低延迟
  • 提高吞吐量
  • 减少Full GC

2. 收集数据

  • GC日志
  • 堆转储
  • 线程dump

3. 分析问题

  • GC频繁
  • 内存泄漏
  • 线程死锁
  • CPU飙高

4. 调整参数

  • 堆大小
  • 垃圾收集器
  • GC参数

5. 验证效果

  • 压力测试
  • 监控指标

常见性能问题及解决?

答案:

1. 内存溢出(OOM)

原因

  • 堆内存不足
  • 内存泄漏
  • 创建大对象

解决

bash
# 增加堆内存
-Xms4g -Xmx4g

# 分析堆转储
jmap -dump:format=b,file=heap.hprof 12345
# 使用MAT分析heap.hprof

2. GC频繁

原因

  • 堆内存过小
  • 对象创建过多
  • 内存泄漏

解决

bash
# 增加堆内存
-Xms2g -Xmx2g

# 调整新生代大小
-Xmn1g

# 调整Survivor比例
-XX:SurvivorRatio=8

3. Full GC频繁

原因

  • 老年代空间不足
  • 元空间不足
  • System.gc()调用

解决

bash
# 增加老年代
-Xms4g -Xmx4g -Xmn1g  # 老年代3g

# 增加元空间
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m

# 禁用System.gc()
-XX:+DisableExplicitGC

4. CPU飙高

排查步骤

bash
# 1. 找到Java进程
jps

# 2. 找到占用CPU高的线程
top -Hp 12345

# 3. 转换线程ID为16进制
printf "%x\n" 1234

# 4. 查看线程堆栈
jstack 12345 | grep -A 20 4d2

5. 内存泄漏

排查步骤

bash
# 1. 生成堆转储
jmap -dump:format=b,file=heap1.hprof 12345
# 等待一段时间
jmap -dump:format=b,file=heap2.hprof 12345

# 2. 使用MAT对比分析
# 查找持续增长的对象

常见原因

  • 集合类未清理
  • 静态集合持有对象
  • 监听器未移除
  • 数据库连接未关闭

调优案例

案例1:接口响应慢

问题:接口响应时间从100ms增加到5s

排查

bash
# 1. 查看GC日志
jstat -gcutil 12345 1000

# 发现Full GC频繁,每次耗时3s

原因:老年代空间不足,频繁Full GC

解决

bash
# 增加堆内存
-Xms4g -Xmx4g

# 使用G1收集器
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200

效果:响应时间恢复到100ms

案例2:内存持续增长

问题:应用运行一段时间后OOM

排查

bash
# 1. 生成堆转储
jmap -dump:format=b,file=heap.hprof 12345

# 2. 使用MAT分析
# 发现ArrayList持有大量对象

原因:静态List未清理,导致内存泄漏

解决

java
// 定期清理
public class Cache {
    private static List<Data> cache = new ArrayList<>();

    public void add(Data data) {
        cache.add(data);
        // 添加清理逻辑
        if (cache.size() > 10000) {
            cache.clear();
        }
    }
}

练习题

  1. 如何排查CPU飙高问题?
  2. 如何排查内存泄漏?
  3. 如何选择合适的垃圾收集器?
  4. 生产环境应该设置哪些JVM参数?

Released under the MIT License.