一、为什么需要JVM调优?
-
- 提高应用性能
- 响应时间:对于许多应用程序,特别是那些需要快速响应用户请求的应用(如Web服务、实时数据处理系统等),减少延迟是至关重要的。通过合适的垃圾收集器选择和内存管理策略,可以显著降低停顿时间。
- 吞吐量:一些应用更关注单位时间内能够处理的任务数量(即吞吐量)。适当的JVM调优可以帮助最大化CPU利用率,从而提高整体吞吐量。
-
- 解决特定问题
- 内存泄漏:不正确的对象引用可能导致内存泄漏,使得程序占用越来越多的内存,最终导致OutOfMemoryError。通过分析堆转储文件并调整堆大小或垃圾回收策略,可以缓解这些问题。
- 频繁的垃圾回收:如果应用程序经历了过于频繁的GC活动,这可能是由于分配了过多短期对象或者堆空间设置不当造成的。通过调整堆大小或选择不同的垃圾收集器,可以减少GC频率及其对应用性能的影响。
-
- 资源利用效率
- CPU使用率:某些垃圾收集算法可能会在GC期间消耗大量CPU资源。选择适合应用负载的垃圾收集器有助于平衡CPU使用与应用性能之间的关系。
- 内存使用:合理配置堆大小和其他内存区域(如永久代/元空间)可避免不必要的内存浪费,并确保系统稳定运行。
-
- 适应不同场景需求
- 不同类型的应用程序(例如批处理作业、在线交易处理系统、实时数据分析等)对性能有不同的要求。根据具体应用场景的需求定制JVM配置,可以更好地满足业务目标。
-
- 降低成本
- 高效的JVM配置可以使同样的硬件资源支持更多的并发用户或更高的工作负载,从而间接降低了运营成本。
大部分情况都是不需要进行JVM调优的。
二、什么时候才需要进行JVM调优?
- 调优指标:
- jvm.gc.time:每分钟的YGC耗时低于1s,500ms以内尤佳;
- jvm.gc.meantime:每次YGC耗时低于100ms,50ms以内尤佳;
- jvm.fullgc.count: FGC最多几小时1次,大于24小时尤佳;
- jvm.fullgc.time: 每次fullgc耗时低于1s,500ms以内尤佳;
如果超过了如上指标才有必要进行JVM调优。
三、如何进行调优?
- 调优工具和命令:

- 常用垃圾回收器

四、实战案例
- 背景描述:
使用 Apache POI 导入excel数据至es中,excel最大可达将近1GB,当文件过大时导入报OOM,且正常导入成功之后,还会出现系统卡顿的情况。 - 监测gc活动
当发现系统卡顿的时候,使用如下命令 jstat -gcutil pid 1000(每隔1s打印1次),查看gc活动是否频繁;
发现FGC(Full GC)次数增加且YGCT(Young GC总时间)、FGCT(Full GC总时间)持续增长,表明存在严重的GC问题。 - 初步调优:
使用-xms1gb -xmx2gb来知道最小堆内存和最大堆内存,解决了oom问题,但是stw依然很长 - 二次调优:
- 由于使用的是jdk1.8,默认的垃圾收集器为parallel gc,该垃圾收集器,stw时间较长,适合大吞吐量、批处理、离线数据分析的应用,不态适合响应时间敏感的应用。所以我们要跟换垃圾回收器,因为服务器的内存只有4GB,所以我们选择CMS垃圾回收器。以此来降低stw时间。
- 使用-XX:+UseConcMarkSweepGC来其余cms垃圾回收器,使用 -Xlog:gc*:file=gc.log:time,uptime,pid,tid,level,tags启用gc日志,通过日志文件可以对gc进行监控,-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 确保仅基于老年代占用率达到70%时触发CMS回收,而不是依赖于JVM的动态计算。;
- 通过查看GC日志文件(如/path/to/gc.log),可以观察到:Full GC次数大幅减少,单次GC停顿时间控制在200ms以内,系统响应恢复正常。