本文主要分享一次生产环境堆内存告警排查分析并解决的实操流程。内容全文 2210 字,预计花 5 分钟读完。
问题背景
最近告警监控群频繁报服务内存使用率大于 90% ,具体告警内容如下:
❝
告警级别: JvmCritical
告警类型: 堆内存使用率告警
告警详情: 服务 npp , 实例 1xx.1x.1x.3x 堆> 内存使用率大于90% ,当前使用率:95.29%
告警节点: 100.1x.1x.3x
故障应用: npp
看到这个问题第一时间联系运维堆现有服务调大内存的参数,由 1G 扩大为 1.5 G 。
扩大以后使用率告警没有之前那么频繁了,但是每天还会出现内存使用率 90%左右的告警。
问题分析
查看近 7 天的堆内存、新生代 Eden 区、老年代的内存使用情况,虽然内存调大了,但是基本都是快使用完才进行GC 。 堆内存监控 老年代内存监控 Eden 内存监控
通过和运维沟通后了解到生产上 JVM 参数并没有做特殊配置。
线上环境使用 JDK 1.8 使用的是默认的垃圾收集器。新生代默认是:Parallel Scavenge 老年代默认是:Parallel Old
Parallel Scavenge 垃圾收集器核心关注吞吐量 gc时间/程序运行总时间 作为依据进行 GC。
这导致新生代和老年代基本是在接近填满时进行 GC, 即上述我们扩大内存后仍然会频繁报内存使用率过高的情况。
Parallel Scavenge 垃圾收集器没有固定的百分比阈值。如果需要减少Full GC的发生,通常需要调整老年代的大小或者调整整个堆的大小。
解决方案
根据上述问题分析可以有 2个解决方案:
-
调整老年代的大小或者调整整个堆的大小 这种方式还是会频繁出现内存告警
-
老年代更换为 CMS 垃圾收集器并配置固定百分比的阈值。
综合分析还是切换为 CMS 垃圾收集器,核心原因如下:
-
CMS 可以配置 固定百分比的阈值
-
Parallel Old 是并行垃圾收集器而 CMS 是并发垃圾收集器, CMS 性能要优于 Parallel Old
关于 CMS 参数配置推荐一个在线配置工具:
https://opts.console.heapdump.cn/
可以通过参数生成快速生成一个比较合理的参数配置 生成jvm 参数
生成的参数具体如下:
-Xmx2688M -Xms2688M -Xmn960M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+CMSClassUnloadingEnabled -XX:+ParallelRefProcEnabled -XX:+CMSScavengeBeforeRemark -XX:ErrorFile=/log/hs_err_pid%p.log -XX:HeapDumpPath=/log -XX:+HeapDumpOnOutOfMemoryError
具体参数介绍如下:
-
-Xmx:最大堆内存
-
-Xms:最小堆内存
-
-Xmn:新生代的大小
-
-XX:MaxMetaspaceSize:最大元空间大小
-
-XX:MetaspaceSize:元空间大小
-
XX:+UseConcMarkSweepGC:使用 CMS 垃圾收集器
-
-XX:+UseCMSInitiatingOccupancyOnly :需要和 CMSInitiatingOccupancyFraction配置使用
-
-XX:CMSInitiatingOccupancyFraction:触发cms gc 的老生代使用率 需要和 UseCMSInitiatingOccupancyOnly 配配合使用
-
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses :当调用 System.gc() 时,JVM 会启动 CMS(Concurrent Mark Sweep)垃圾收集器的并发收集,并尝试卸载不再需要的类。如果没有配置 JVM 将执行全堆的垃圾收集,而不是并发收集,也不会尝试卸载类。
-
-XX:+CMSClassUnloadingEnabled :CMS 的垃圾收集周期中,JVM 会尝试卸载不再需要的类
-
-XX:+ParallelRefProcEnabled :-XX:+ParallelRefProcEnabled,那么在垃圾收集过程中,JVM 会并行处理这些引用对象(SoftReference、WeakReference、FinalReference),从而提高垃圾收集的效率
-
-XX:+CMSScavengeBeforeRemark :CMS 的重新标记(Remark)阶段之前,JVM 会先执行一次新生代的垃圾收集。这样做的目的是减少重新标记阶段的工作量
-
XX:+HeapDumpOnOutOfMemoryError:当 JVM 遇到 OutOfMemoryError 时是否生成堆转储文件(heap dump)。
优化后的效果
优化后效果明显,一天内没有再出现内存使用 90%左右告警,优化前后具体内存效果对比如下:
堆内存优化前后内存变化。 jvm 堆内存优化前后对比
优化前使用的是 Parallel Old 垃圾收集器 近 7天内存变化。 优化前老年代
优化后 CMS 垃圾收集器内存变化。 优化后老年代 - END -