JVM调优

一、先搞懂:JVM 调优调的是什么?

JVM 调优的核心目标:
减少 Full GC 次数(Full GC 会暂停所有业务线程,导致系统卡顿);
控制 Young GC 频率和耗时(Young GC 轻量,但太频繁也会影响性能);
避免内存泄漏 / 溢出(OOM);
提升内存利用率(既不浪费内存,也不频繁回收)。
调优的本质:合理分配堆内存各区域大小 + 选择合适的垃圾收集器 + 监控并优化内存使用。

二、JVM 调优前置:必须懂的内存模型(极简版)

不用记复杂结构,核心记住堆内存的划分:

堆内存(Heap)
├── 年轻代(Young Generation) 占堆的 1/3 ~ 1/2
│ ├── Eden 区(伊甸园):新对象诞生地(占年轻代 80%)
│ ├── Survivor 0(S0):存活对象临时区
│ └── Survivor 1(S1):和 S0 互换使用
└── 老年代(Old Generation) 占堆的 1/2 ~ 2/3
└── 存放存活时间长的对象(年轻代熬过来的)

Young GC:Eden 满了触发,回收年轻代,存活对象移到 Survivor / 老年代;
Full GC:老年代满了触发,回收整个堆(年轻代 + 老年代),性能开销极大。

三、JVM 调优三步法(新手也能落地)

第一步:监控(先找问题,再调优!)
调优不是瞎改参数,先通过工具定位问题:

  1. 基础工具(JDK 自带,无需安装)


    image.png

    2.企业级工具
    Arthas(阿里开源):线上排查神器,一键查看 GC、内存、线程;
    Prometheus + Grafana:长期监控 JVM 指标(GC 次数、内存使用率)。


    image.png

    新手避坑:别用 CMS(老年代收集器,已废弃)、Serial GC(单线程,性能差)。

第三步:调整核心参数(实战!)

参数不用多,记住核心 8 个就够,以下是 G1GC 调优模板(微服务通用):

# 1. 堆内存大小(必设,固定值,避免JVM自动调整)
-Xms4g          # 初始堆内存(和-Xmx一致,避免内存扩容卡顿)
-Xmx4g          # 最大堆内存(根据服务器内存设置,如8G服务器设4g)

# 2. 年轻代比例(G1GC 推荐)
-XX:G1NewSizePercent=20    # 年轻代最小占比
-XX:G1MaxNewSizePercent=50 # 年轻代最大占比

# 3. GC 停顿时间目标(G1GC 核心)
-XX:MaxGCPauseMillis=200   # 目标停顿时间(200ms,可根据业务调整)

# 4. 老年代占比阈值(触发混合回收)
-XX:InitiatingHeapOccupancyPercent=45 # 堆内存占45%时触发老年代回收

# 5. 日志配置(必加!排查问题用)
-Xlog:gc*:file=gc.log:time,level,tags # JDK 11+ 日志格式
# JDK 8 替代:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log

# 6. 其他优化
-XX:+HeapDumpOnOutOfMemoryError # OOM 时自动导出堆快照
-XX:HeapDumpPath=/tmp/heap.hprof # 快照保存路径
-XX:+UseG1GC                    # 指定 G1GC(JDK 11+ 默认)

四、企业级调优实战案例(从问题到解决)

问题场景:
微服务接口偶尔卡顿,查看 GC 日志发现Full GC 频繁(每小时 10 次),Young GC 也很频繁(每分钟 5 次)。
排查步骤:
用 jstat -gc 进程ID 查看:
Eden 区很小(仅 512M),导致 Young GC 频繁;
老年代占比快速上涨,触发 Full GC。
用 jmap -histo 进程ID 查看:
发现大量字符串对象未释放(可能是内存泄漏)。

五、新手调优避坑指南

别盲目调大堆内存:比如 8G 服务器设 - Xmx8g,会导致 Full GC 耗时更长(一次 Full GC 可能卡 10 秒);
别乱加参数:比如 -XX:+UseConcMarkSweepGC(CMS 已废弃),反而出问题;
调优后一定要监控:改完参数后,观察 1-2 天 GC 日志,确认效果;
优先优化代码:内存泄漏、大对象创建(如一次性加载 10 万条数据),比调参数更有效。

六、通用调优模板(直接复制用)

#1. 微服务(JDK 11+,G1GC)
java -jar \
-Xms4g \
-Xmx4g \
-XX:G1NewSizePercent=20 \
-XX:G1MaxNewSizePercent=50 \
-XX:MaxGCPauseMillis=200 \
-XX:InitiatingHeapOccupancyPercent=45 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/tmp/heap.hprof \
-Xlog:gc*:file=gc.log:time,level,tags \
your-app.jar

#2. 单机应用(JDK 8,Parallel GC)
java -jar \
-Xms2g \
-Xmx2g \
-XX:NewRatio=2 \ # 年轻代:老年代 = 1:2
-XX:SurvivorRatio=8 \ # Eden:S0:S1 = 8:1:1
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-Xloggc:gc.log \
-XX:+HeapDumpOnOutOfMemoryError \
your-app.jar

七、其他工具

Arthas 阿尔萨斯
jvisualvm(VisualVM) 是 JDK 自带的图形化 JVM 监控与分析工具,能直观看到 CPU、堆内存、新生代 / 老年代、GC、线程、类加载 的实时曲线,完全图形化,不用记命令。


image.png

核心图形化面板(对应你关心的内存 / GC)

  • CPU:实时 CPU 使用率曲线

  • 堆内存 Heap:总大小、已使用、空闲 → 看是否持续上涨(泄漏)

  • 类加载:加载类数量

  • 线程:活动线程数

  • 按钮

    • Perform GC:手动触发 Full GC(测试回收效果)
    • Heap Dump:生成堆快照(排查 OOM / 泄漏)

Visual GC:
Eden:新生代 Eden 区曲线(对象创建区)
S0/S1:Survivor 区
Old:老年代(你关心的 FullGC 区)
Metaspace:元空间
GC Time:Minor GC / Full GC 耗时、次数
一眼判断:
Eden 涨太快 → 对象创建过多
Old 持续涨、FullGC 后不下降 → 内存泄漏
FullGC 频繁、耗时高 → 性能瓶颈
「线程(Threads)」图形
线程状态图:运行、休眠、等待、阻塞
线程数曲线:是否无限增长(线程泄漏)
死锁自动标红:直接看到死锁线程
「采样器(Sampler)」(定位热点)
CPU 采样:图形化看哪个方法最耗 CPU
内存采样:哪个类创建对象最多、占用最大(定位你说的 new 过多)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容