如何优化生产环境的Full GC?

简介: 大部分工程师开发完一个系统后,部署生产环境的时候往往不对JVM进行参数设置,直接用默认JVM参数,这绝对是系统负载逐渐增高的时最大问题如你不设置-Xmx、-Xms之类的堆内存大小,你启动一个系统,可能默认就给你几百MB的堆内存大小,新生代和老年代可能都是几百M。

大部分工程师开发完一个系统后,部署生产环境的时候往往不对JVM进行参数设置,直接用默认JVM参数,这绝对是系统负载逐渐增高的时最大问题


如你不设置-Xmx、-Xms之类的堆内存大小,你启动一个系统,可能默认就给你几百MB的堆内存大小,新生代和老年代可能都是几百M。


很多后台系统都用默认JVM参数部署启动,前期没啥问题,但中后期开始,当有一定用户量和一定负载,就会出现惊喜。


Eden过小,导致频繁触发YGC,Survivor过小,导致经常在YGC后存活对象其实也没多少,但Survivor放不下,导致对象经常进入老年代,导致老年代过段时间就满,然后触发Full GC。


所以当时这个垂直电商APP的各个系统通过jstat分析JVM GC后发现,高峰期Full GC每小时发生好几次。Full GC正常以天为单位发生,如每天发生一次或几天发生一次。要是每h都发生几次Full GC,就会导致系统每h卡顿好几次!


公司级别JVM参数模板


让大部分系统套用这个模板,基本保证JVM性能别太差,避免很多初中级工程师直接使用默认的JVM参数,可能一台8G内存的机器上,JVM堆内存就分配了几百MB。


-Xms4096M

-Xmx4096M

-Xmn3072M

-Xss1M

-XX:PermSize=256M

-XX:MaxPermSize=256M

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC

-XX:CMSInitiatingOccupancyFaction=92

-XX:+UseCMSCompactAtFullCollection

-XX:CMSFullGCsBeforeCompaction=0


8G机器给JVM堆分配4G,毕竟还有其他进程使用内存,别让JVM堆把机器内存占满。


年轻代给到3G,让年轻代尽量大,进而让每个Survivor区域都达到300MB。根据当时对这个业务系统的分析,假设用默认的JVM参数,可能年轻代就几百MB的内存,Survivor区域就几十M。


那每次GC后,存活对象可能几十M,因为在GC瞬间可能有部分请求没处理完,此时会有几十M对象存活,所以很容易触发动态年龄判定规则,让部分对象进入老年代。


所以分析后,给年轻代更大内存空间,让Survivor更大,这样在YGC时,这瞬间可能有部分请求没处理完,有几十M存活对象,这时候在几百M的Survivor可轻松放下,而不会进老年代。这样操作对垂直电商大部分后台业务都能cover。


不同系统运行时情况略不同,但基本上都是在每次YGC后存活几~几十M对象,所以此时在这个参数模板下都能抗住。


只要把内存分配完毕,那对象进入老年代速度就很慢,经过该参数模板在朋友公司全部系统的重新部署和上线,各个团队通过jstat观察,基本上发现各个系统的Full GC都变成了几天才会发生一次。


此时在参数模板里还会加入Compaction相关参数,保证每次Full GC后都会执行一次压缩,解决内存碎片。


如何优化每次Full GC的性能?


就是把每次Full GC时间进一步降低。


-XX:+CMSParallelInitialMarkEnabled,会在CMS的“初始标记”阶段开启多线程并发执行


初始标记阶段,会STW,该阶段开启多线程并发后,可尽可能优化该阶段性能,减少STW时间。


-XX:+CMSScavengeBeforeRemark


在CMS重新标记阶段前,先尽量执行一次YGC


这样做有什么作用呢?


CMS重新标记也会STW,所以重新标记前,先执行一次YGC,就会回收掉一些年轻代里无人引用的对象。


所以若提前回收掉一些对象,在CMS重新标记阶段就能少扫描一些对象,这就提升CMS重新标记阶段的性能。


-Xms4096M -Xmx4096M -Xmn3072M -Xss1M

-XX:PermSize=256M

-XX:MaxPermSize=256M

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC

-XX:CMSInitiatingOccupancyFaction=92

-XX:+UseCMSCompactAtFullCollection

-XX:CMSFullGCsBeforeCompaction=0

-XX:+CMSParallelInitialMarkEnabled

-XX:+CMSScavengeBeforeRemark


采用JVM参数模板后的效果


采用jstat观察JVM GC情况,发现好转,各系统:


YGC都在几min或十几min一次,每次耗时就几十ms

Full GC基本都在几天一次,每次耗时在几百ms

JVM达到这个性能就对线上系统没多大影响。


目录
相关文章
|
5月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
154 0
|
3月前
|
监控 Java 测试技术
JVM 性能调优 及 为什么要减少 Full GC
JVM 性能调优 及 为什么要减少 Full GC
94 4
|
3月前
|
Java BI 运维
开发与运维配置问题之升级机器配置后出现频繁的GC问题和超长的GC时间如何解决
开发与运维配置问题之升级机器配置后出现频繁的GC问题和超长的GC时间如何解决
29 1
|
3月前
|
Java 运维
开发与运维内存问题之触发Full GC,类加载检查如何解决
开发与运维内存问题之触发Full GC,类加载检查如何解决
25 0
|
3月前
|
人工智能 Java
JVM内存问题之当老年代缓慢增加且Full GC无法清除时,应如何使用MAT进行分析
JVM内存问题之当老年代缓慢增加且Full GC无法清除时,应如何使用MAT进行分析
116 0
|
4月前
|
运维 Java Shell
手工触发Full GC:JVM调优实战指南
本文是关于Java应用性能调优的指南,重点介绍了如何使用`jmap`工具手动触发Full GC。Full GC是对堆内存全面清理的过程,通常在资源紧张时进行以缓解内存压力。文章详细阐述了Full GC的概念,并提供了两种使用`jmap`触发Full GC的方法:通过`-histo:live`选项获取存活对象统计信息,或使用`-dump`选项生成堆转储文件以分析内存状态。同时,文中也提醒注意手动Full GC可能带来的性能开销,建议在生产环境中谨慎操作。
|
5月前
|
运维 JavaScript Java
Serverless 应用引擎产品使用之Nacos 在集中发版时遇到老年代暂满,并且频繁进行 Full GC,但是 GC 后内存没有降下来如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
141 0
|
5月前
|
存储 Java
jvm性能调优实战 - 23 模拟Young GC的发生及分析GC日志
jvm性能调优实战 - 23 模拟Young GC的发生及分析GC日志
94 0
|
算法 安全 Java
【JVM性能优化】CMS回收器的Full-GC流程分析以及问题探究
【JVM性能优化】CMS回收器的Full-GC流程分析以及问题探究
754 0
【JVM性能优化】CMS回收器的Full-GC流程分析以及问题探究
|
Arthas Prometheus 监控
排查GC问题常用的工具
最近杭州的花都陆陆续续开了。本来打算去太子湾看看郁金香,但到了地方才发现太子湾人满为患,无预约不能进。于是就在西湖边逛了逛,拍了点花花草草的照片。
775 0