记一次JVM调优

本文记录了一次针对OA系统的JVM调优过程。系统在运行一段时间后变得卡顿,经过分析发现是由于年老代内存满导致Full GC,从而影响系统性能。通过对JVM参数的调整,如增大年轻代内存、设置CMS垃圾回收机制,以及调整CMSInitiatingOccupancyFraction和SurvivorRatio,成功避免了Full GC引发的系统卡死,优化后系统运行稳定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前情:8月1日到新公司入职,到职第一天上级就分配了任务,优化OA。
OA目前的情况:运行一段时间后就会很卡,打开流程或表单一直处于刷新状态,只有重启tomcat服务后才能恢复正常。开始想从oracle数据库入手,确认是不是oracle数据量太大未做优化导致的,导出awr报表做分析,结果实在是看不太懂,只好放弃,转从tomcat入手。

tomcat服务器信息:

系统版本CPU核数内存容量
Red Hat 4.8.5-42064G

jdk信息:

versionSE RunTIme EnvironmentHotSpot
1.6.0-31build 1.6.0_31-b0464-Bit Server VM (build 20.6-b01, mixed mode)

tomcat信息:

版本
6.0.35

公司目前在职员工8000人左右,同时在线人数2500人左右。
首先查看原来的JVM设置:

JAVA_OPTS="
-server 
-Xms16000m 
-Xmx16000m 
-XX:PermSize=1024M 
-XX:MaxNewSize=1024m 
-XX:MaxPermSize=1024m 
-Djava.awt.headless=true "

可以看出配置了堆的大小16000M,大约15.5G左右,最大年轻代1G,永久堆内存1G,我们通过VisualVM可以更直观的看到整个内存的分配情况:
这里写图片描述

注:这是后面模拟当时的服务器信息的截图,调优时没有截图。

通过查询资料及百度然后对JVM做了第一次优化:

JAVA_OPTS="
-server 
-Xms16000M 
-Xmx16000M 
-Xss256k 
-XX:NewSize=2048M 
-XX:MaxNewSize=2304M 
-XX:PermSize=2048M
-XX:MaxPermSize=2304M  
-XX:+AggressiveOpts 
-XX:+UseBiasedLocking 
-XX:+DisableExplicitGC 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:MaxTenuringThreshold=31 
-XX:+CMSParallelRemarkEnabled 
-XX:+UseCMSCompactAtFullCollection 
-XX:LargePageSizeInBytes=128m 
-XX:+UseFastAccessorMethods 
-XX:+UseCMSInitiatingOccupancyOnly
-Duser.timezone=Asia/Shanghai 
-Djava.awt.headless=true
-Dcom.sun.management.jmxremote 
-Djava.rmi.server.hostname=192.168.0.99 
-Dcom.sun.management.jmxremote.port=8010 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false"

xms和xmx没有做改动,还是16000M,增加了xss:每个线程的堆栈大小,加大了年轻代的内存,设置垃圾回收机制CMS,其他参数就不一一解释了,我们看看优化后的情况:

这里写图片描述

可以看到eden区明显的增大了,old区缩小了一些,perm gen(永久代)有增加,下面多了一列Histogram,这是-XX:MaxTenuringThreshold=31 参数设置后的效果,表示survivor的存活生命周期。这次优化后并没有达到效果,下午访问量大的时候old区很快就满了,然后OA打开流程或表单一直在刷新,要保存的数据也没法保存。

虽然失败了,但是经错这次优化发现了OA访问卡死的原因:old即年老代内存满了,触发了Full GC,然后就是大家说的stop the world,所有线程等待Full GC完成后才能重新访问,自然OA无法访问甚至直接客户端浏览器卡死。既然知道原因了那就对症下药。又是一通百度查寻各种网上的方案。
既然是年老代满了那么就加大年老代不就行了,通过事实验证只是加大年老代是不行的,因为总有一天它还是会满的,那有没有方案能在它满之前就先执行垃圾回收,释放内存呢?答案是肯定可以的。通过配置-XX:CMSInitiatingOccupancyFraction=73可以设置当年老区满多少的时候进行垃圾回收,这里我设置的73%,并不时随便设置的,通过这个公式可以计算出来:

CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

查询资料还发现,可以通过加大survivor区来达到一些对象在未到达年老代就被回收掉,可以通过设置-XX:SurvivorRatio=3参数来达到效果,然后再一次进行优化:

JAVA_OPTS="
-server 
-Xms20480M 
-Xmx20480M 
-Xss256k 
-XX:NewSize=5120M 
-XX:MaxNewSize=5120M 
-XX:PermSize=256M
-XX:MaxPermSize=256M  
-XX:SurvivorRatio=3
-XX:+AggressiveOpts 
-XX:+UseBiasedLocking 
-XX:+DisableExplicitGC 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:+CMSParallelRemarkEnabled 
-XX:+UseCMSCompactAtFullCollection 
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:LargePageSizeInBytes=128m 
-XX:+UseFastAccessorMethods 
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=73
-XX:SoftRefLRUPolicyMSPerMB=0
-verbose:gc 
-XX:+PrintGCTimeStamps 
-XX:+PrintGCDetails 
-Xloggc:/usr/local/tomcat/temp/gc.log
-Duser.timezone=Asia/Shanghai 
-Djava.awt.headless=true
-Dcom.sun.management.jmxremote 
-Djava.rmi.server.hostname=192.168.0.99 
-Dcom.sun.management.jmxremote.port=8010 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false"

这次显示增大了整个堆内存,然后增加了survivor的比例,设置了CMS垃圾回收在73%时自动回收,这时服务器的最终效果如下:
这里写图片描述

通过设置-Xloggc:/usr/local/tomcat/temp/gc.log,可以查看到GC的相关日志。
这次优化后跟踪了2天,占时没出现old区满的情况,当达到73%时会自动执行垃圾回收,由于是并行的,所以对整个OA的访问并不影响。这样的优化应该还有改进的地方,后面我会继续跟踪并优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值