JVM调优指南

张开发
2026/5/5 6:23:30 15 分钟阅读
JVM调优指南
JVM调优是Java性能优化的核心技能目标是减少GC暂停、提高吞吐量、避免内存溢出。一、调优前准备1. 明确目标吞吐量优先后台批处理、大数据计算低延迟优先互联网应用、实时系统内存占用优先资源受限环境2. 监控工具# 命令行工具 jps # 查看Java进程 jstat # 监控GC情况 jmap # 内存快照 jstack # 线程快照 jinfo # 查看JVM参数 # 可视化工具 jconsole # JMX监控 jvisualvm # 综合监控 JMC # Java Mission Control Arthas # 阿里开源诊断工具3. JVM运行情况预估年轻代对象增长速率每秒多少对象进入Eden区Young GC触发频率和每次耗时Young GC后多少对象存活和进入老年代Full GC触发频率和每次耗时二、核心参数详解1. 内存设置# 堆内存 -Xms4g # 初始堆大小 -Xmx4g # 最大堆大小 -Xmn2g # 年轻代大小 -XX:NewRatio2 # 老年代/年轻代比例默认2 -XX:SurvivorRatio8 # Eden/Survivor比例默认8 # 元空间JDK8 -XX:MetaspaceSize256m # 初始元空间 -XX:MaxMetaspaceSize256m # 最大元空间 # 直接内存 -XX:MaxDirectMemorySize1g # NIO直接内存2. GC调优参数# Parallel GC -XX:ParallelGCThreads4 # GC线程数 -XX:MaxGCPauseMillis200 # 目标最大GC暂停时间 -XX:GCTimeRatio99 # 吞吐量目标99%应用时间 # CMS -XX:CMSInitiatingOccupancyFraction70 # CMS触发阈值 -XX:UseCMSInitiatingOccupancyOnly # 使用指定阈值 # G1 GC -XX:MaxGCPauseMillis200 # 期望暂停时间 -XX:G1HeapRegionSize16m # Region大小1-32M -XX:InitiatingHeapOccupancyPercent45 # 触发并发GC的堆占用率 -XX:G1NewSizePercent5 # 年轻代最小比例 -XX:G1MaxNewSizePercent60 # 年轻代最大比例三、GC日志分析1. 启用GC日志# JDK8 -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintGCTimeStamps -Xloggc:gc.log -XX:UseGCLogFileRotation -XX:NumberOfGCLogFiles10 -XX:GCLogFileSize100M # JDK9 -Xlog:gc*:filegc.log:time,uptime,level,tags:filecount10,filesize100M2. 日志解读# Parallel GC日志示例 [GC (Allocation Failure) [PSYoungGen: 51200K-7168K(59392K)] 51200K-15120K(196608K), 0.0123456 secs] # 解读 # - 年轻代51200K - 7168K总大小59392K # - 堆总51200K - 15120K总大小196608K # - 耗时0.0123456秒 # G1 GC日志 [GC pause (G1 Evacuation Pause) (young), 0.0152345 secs] [Parallel Time: 12.3 ms, GC Workers: 8] ... [Eden: 512M(512M)-0B(512M) Survivors: 64M-64M Heap: 800M(2048M)-450M(2048M)]四、常见问题场景调优场景1频繁Full GC# 问题系统响应慢CPU飙升 # 排查步骤 jstat -gcutil pid 1000 # 查看GC频率 # 解决方案 # 1. 增大堆内存 -Xms4g -Xmx4g # 2. 调整对象晋升阈值 -XX:MaxTenuringThreshold15 -XX:TargetSurvivorRatio90 # 3. 使用G1 GC -XX:UseG1GC -XX:MaxGCPauseMillis100场景2内存泄漏# 生成堆转储 jmap -dump:live,formatb,fileheap.hprof pid # 自动触发OOM时dump -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/path/to/dump # 分析工具Eclipse MAT、JProfiler、VisualVM场景3GC暂停时间过长# 目标从200ms降到50ms # G1调优方案 -XX:UseG1GC -XX:MaxGCPauseMillis50 # 降低目标暂停时间 -XX:G1NewSizePercent10 # 增大年轻代 -XX:G1HeapRegionSize8m # 调整Region大小 -XX:ConcGCThreads4 # 增加并发GC线程场景4动态年龄判断机制导致Full GC频繁# jstat -gcutil观察到的现象 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 98.22 45.33 85.60 92.33 89.21 125 2.345 89 5.678 8.023 # 特点YGC次数少FGC次数异常多几乎每次YGC后都伴随FGC # 老年代占用85%但实际存活对象并不多根本原因JVM的动态年龄判断机制当Survivor区中相同年龄的所有对象大小总和 Survivor区的一半时年龄大于等于该年龄的对象直接晋升到老年代。解决方案调整Survivor区大小调整动态年龄阈值增大年轻代空间场景5老年代空间担保机制导致Full GC Minor GC# jstat -gcutil观察到的异常现象 S0 S1 E O M YGC YGCT FGC FGCT GCT 0.00 5.22 92.33 45.60 78.33 15 0.345 89 5.678 6.023 # 关键指标 # YGC15次FGC89次 → FGC远超YGC正常情况下YGC应该远多于FGC # Eden区92% → 频繁触发YGC # 老年代仅45% → 老年代空间充足但仍然FGC # GC日志特征 [GC (Allocation Failure) [PSYoungGen: 51200K-0K(59392K)] 51200K-50200K(196608K), 0.1234567 secs] [Full GC (Ergonomics) [PSYoungGen: 0K-0K(59392K)] [ParOldGen: 50200K-45000K(137216K)] 50200K-45000K(196608K), 0.4567890 secs] # 注意每次YGC后立即跟随FGC根本原因老年代空间担保机制在YGC前JVM检查老年代最大连续空间是否大于年轻代所有对象总空间。如果不足为避免YGC失败直接触发Full GC。解决方案增大老年代空间# 原配置问题配置 -Xms4g -Xmx4g -Xmn2g # 老年代2G -XX:UseParallelGC # 优化方案A整体增大堆内存 -Xms8g -Xmx8g -Xmn2g # 老年代从2G增加到6G增加3倍 -XX:UseParallelGC # 优化方案B调整年轻代比例不增加总堆减少年轻代 -Xms4g -Xmx4g -Xmn1g # 年轻代从2G减少到1G老年代从2G增加到3G -XX:NewRatio3 # 老年代:年轻代3:1老年代3G年轻代1G -XX:UseParallelGC

更多文章