1 资料
2 gc日志打印
gc调优是个很实验很伽利略的活儿,gc日志是先决的数据参考和最终验证:
-xx: printgcdetails -xx: printgctimestamps(gc发生的时间) -xx: printgcapplicationstoppedtime(gc消耗了多少时间) -xx: printgcapplicationconcurrenttime(gc之间运行了多少时间)
3 收集器选择
cms收集器:暂停时间优先
配置参数:-xx: useconcmarksweepgc
已默认无需配置的参数:-xx: useparnewgc(parallel收集新生代)
-xx: cmspermgensweepingenabled(cms收集持久代)
-xx:usecmscompactatfullcollection(full gc时压缩年老代)
初始效果:1g堆内存的新生代约60m,minor gc约5-20毫秒,full gc约130毫秒。
parallel收集器:吞吐量优先
配置参数: -xx: useparallelgc -xx: useparalleloldgc(parallel收集年老代,从jdk6.0开始支持)
已默认无需配置的参数: -xx: useadaptivesizepolicy(动态调整新生代大小)
初始效果:1g堆内存的新生代约90-110m(动态调整),minor gc约5-20毫秒,full gc有无useparalleloldgc 参数分别为1.3/1.1秒,差别不大。
另外-xx:maxgcpausemillis=100 设置minor gc的期望最大时间,jvm会以此来调整新生代的大小,但在此测试环境中对象死的太快,此参数作用不大。
4 调优实战
parallel收集高达1秒的暂停时间基本不可忍受,所以选择cms收集器。
在被压测的mule 2.0应用里,每秒都有大约400m的海量短命对象产生:
- 因为默认60m的新生代太小了,频繁发生minor gc,大约0.2秒就进行一次。
- 因为cms收集器中maxtenuringthreshold(生代对象撑过过多少次minor gc才进入年老代的设置)默认0,存活的临时对象不经过survivor区直接进入年老代,不久就占满年老代发生full gc。
对这两个参数的调优,既要改善上面两种情况,又要避免新生代过大,复制次数过多造成minor gc的暂停时间过长。
- 使用-xmn调到1/3 总内存。观察后设置-xmn500m,新生代实际约460m。(用-xx:newratio设置无效,只能用 -xmn)。
- 添加-xx: printtenuringdistribution 参数观察各个age的对象总大小,观察后设置-xx:maxtenuringthreshold=5。
优化后,大约1.1秒才发生一次minor gc,且速度依然保持在15-20ms之间。同时年老代的增长速度大大减缓,很久才发生一次full gc,
参数定稿:
-xms1024m -xmx1024m -xmn500m -xx: useconcmarksweepgc -xx:maxtenuringthreshold=5 -xx: explicitgcinvokesconcurrent
最后服务处理速度从1180 tps 上升到1380 tps,调整两个参数提升17%的性能还是笔很划算的买卖。