记一次JVM调优

来源:互联网 发布:json文件怎么打开 编辑:程序博客网 时间:2024/05/18 20:51

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

tomcat服务器信息:

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

jdk信息:

version SE RunTIme Environment HotSpot 1.6.0-31 build 1.6.0_31-b04 64-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的访问并不影响。这样的优化应该还有改进的地方,后面我会继续跟踪并优化。

原创粉丝点击