记一次JVM调优之旅(斗争full gc)

俗话说技多不压身,当年苦读《深刻理解JVM》还专门整理了笔记,如今就用上了~html

笔记 http://www.cnblogs.com/syjkfind/p/3901774.htmljava

【症状】 用户操做数据导出时总会发生卡顿,后台占内存的定时任务发生时也会。JVM参数就不贴了,比较普通且相对合理。数据库

【思路】缓存

查gc日志是发生了full gc,tomcat日志零零散散有不少exception。tomcat

另外凭着对代码的了解,触发时同时刻的日志显示正在执行较大数据量的查询并且装载进JVM,方法调用和临时变量也不少。服务器

【分析】框架

1.minor gc很频繁,但时间短因此问题不大,触发缘由基本都是申请空间失败。运维

2.偶尔有System.gc(),时间大概1分钟。代码中没有显式调用,基本肯定是监控程序RMI访问触发的。能够加参数禁用 -XX:+DisableExplicitGC 。异步

3.时常有promotion failed,即在minor gc时年轻代的存活区空间不足而进入老年代,老年代又空间不足而触发full gc。时间大概3分钟。解决思路一种是增大存活区,一种则相反是去掉存活区增大老年代。相关参数通常有:大数据

-XX:SurvivorRatio=32 存活区除以伊甸区的比率,存活区有from和to两个,因此这里的意思是单个存活区占年轻代的1/34;

-XX:OldSize=60M 老年代大小;

-XX:MaxTenuringThreshold=15 即多少次minor gc后存活的年轻代对象会晋升老年代。

4.常常有concurrent mode failure,即CMS执行过程当中老年代空间不足,这时会变成Serial Old收集器致使更长时间的停顿。时间大概5分钟。其中引起这一问题的状况多是浮动垃圾太多、多是CMS收集器自己也占用堆空间、也多是老年代太多碎片,但都是CMS收集器的特性致使的。相关配置通常有:

-XX:CMSInitiatingOccupancyFraction=80 即老年代满80%时触发CMS(full gc),调高则full gc相对减小,调低则full gc处理得比较快;

-XX:UseCMSCompactAtFullCollection 或 -XX:CMSFullGCsBeforeCompaction=5 即full gc前或后作碎片整理。

5.另有个有趣的文章,过多过长的exception会致使promotion failed

http://www.th7.cn/Program/java/201511/685711.shtml

可能挺符合咱们的场景的,没有运维权限,下次能够考虑找运维dump个分析一下对象。

之前为了追踪错误关闭了“快抛” -XX:-OmitStackTraceInFastThrow 即反复出现的exception不会用一个静态的没堆栈信息的实例去代替,这个要权衡一下了。

【解决】

建立不少对象占了年轻代?大对象致使占满老年代?浮动垃圾(CMS时继续在产生临时对象)或老年代碎片?

调优多少是能够改善的,但彷佛代码自己更有问题,恐怕分配再多的内存都不够吃。好比没有应用较完善的一级缓存二级缓存,好比常常粗暴地把上万条记录加载进来,还没作分页,还有藏的比较深的作了切面触发异步服务把异步服务队列占满了。初期享受了框架的便利而考虑设计的少,而如今则要开始还技术债务了~

所幸的是在有限的时间里,咱们有简单粗暴有效的方法缓解这些问题:加服务器,把大任务剥离出来~

而中长期的考虑来看,在不改变现有框架的前提下,整改exception、整改业务代码作分页、封装数据库分页查询框架、改造数据库层二级缓存(集群范围内缓存)会是比较有效的措施。

更长远的确定就是回归Spring系主流框架,再者进军服务化了。。。但那个几乎要把业务代码从新写一遍,是后话了。

回归主题若是是调优来解决问题,最好是dump了作更深刻的分析。主观上看来启用快抛、gc后碎片整理、增大存活区应该是比较有针对性的调整,而CMSInitiatingOccupancyFraction取值和CMS各阶段细致的配置则须要更量化的分析。

相关文章
相关标签/搜索