一、现象

某系统每台机器每天都会出现一次fgc时间过长的告警。

二、分析

1.查看监控,发现每天无规律的会发生达到5-7秒的fgc。

注:该监控上的fullgc监控采用的是jmx的统计方式,所以其实是对oldgc的监控,因为除了CMS和
G1以外的垃圾回收器的old gc只能由fullgc触发,所以大部分情况下oldgc次数就是fullgc次数,
oldgc时间接近于fullgc时间。 

2.查看对应fgc时间点的gc日志,发现全部都发生了promotion fail,确认是晋升失败引起过长的fgc(Old Serial gc)

从gc日志可知,可用年轻代2516544K,发生promotion fail的时候年轻代几乎没有回收对象(从2274227K到2270163K只减少了4064K),年轻代剩余可用空间2516544K-2270163K=246381K<2270163K,年轻代空间不足,需要提前晋升到年老代2270163K-246381K=2023782K。年老代此时剩余可用空间5592448K-4276438K=1316010K,小于2023782K,年老代不足,晋升失败,触发fgc。

注:promotion fail(晋升失败)
eden区空间不足引起ygc,ygc后eden和survivor区回收不了的对象,需要复制到另外一个survivor区,
这个时候发现这个survivor区空间不足以容纳这些对象,发生提前晋升到老年代,老年代也容纳不了这些
对象,从而触发了fgc(CMS不提供fgc方案,所以使用的是串行fgc,效率可见而知。G1垃圾回收器也是如此)产生promotion fail的可能原因:
1.年轻代太小,需要调大年轻代
2.年老代太小,需要调大年老代
3.年老代空间充足,但有内存碎片,需要开启内存碎片整理

三、解决过程

分析JVM参数

-server -Xms8192m -Xmx8192m -XX:MaxMetaspaceSize=256m 

可以看出,原来的JVM参数除了设置堆大小和方法区大小,其它的配置都是使用默认值,即各个分区大情况(整堆大小:8192m):

年轻代大小:8192m*1/3=2796160K

年老代大小:8192m*2/3=5592448K

年轻代eden区大小: 2796160K*8/10 = 2236928K

年轻代survivor区大小:2796160K*2/10=559232K

可用年轻代大小:eden区+单个surviror区=2236928K+279616K=2516544K

排除是由于内存碎片而导致的promotion fail

1、默认已经开启内存碎片整理:-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

2、从名字服务/sunfire监控上看内存情况也可以知道old gc都发生在使用率达到90%,也符合-XX:CMSInitiatingOccupancyFraction默认值是90的配置。

第一次调优

考虑到业务是对App提供服务,理论上很多对象都是短生命对象,因而思路一是加大年轻代,提供更大的ygc空间,让对象尽可能在年轻代回收,避免对象晋升到老年代。

jvm参数调整

-server -Xms8192m -Xmx8192m -Xmn4g -XX:MaxMetaspaceSize=256m

加大年轻代空间到4g,有可能加快old gc频率,所以加大年轻代的前提是老年代原来的old gc频率不是很高:如下图,>2小时一次oldgc)

效果

ygc每分钟减少2~5次,但每天仍然会有1到2次的promotion fail发生。

结论

第一次调优失败。

第二次调优

分析第一次调优后的gc日志发现,发生promotion fail的时候年轻代的空间几乎没被回收,怀疑会不会有大对象瞬间堆积(从监控上观察内存使用情况,排除了内存溢出的可能)。因而希望在发生fgc的时候能知道当时内存的使用情况。

jvm参数调整:

-server -Xms8192m -Xmx8192m -Xmn4g -HeapDumpBeforeFullGC -XX:MaxMetaspaceSize=256m

在即将发生fgc之前dump内存,dump文件没指定路径则存放在当前目录。

结果:

11.17号02:27分dump出了一份fgc的内存快照:

http://xxx.xxx.cn/service/index.html#/zprofiler/heap/upload-20181117023059185-zprofiler-heap.675B.bin/overview

分析:

借助zprofile分析,确实没有可疑的内存溢出。分析类簇,发现ConcurrentSkipListMap$Node和ConcurrentHashMap$Node各占了1.2g和1.8g。继续跟踪,发现很多CacheStatState和DBStatState,这个是框架里的缓存和数据库统计对象,会在内存堆积60秒后再写入磁盘:

基于上面的分析,业务上缓存和数据库查询使用得很多(无法短时间内减少统计对象),框架也不再提供更新(无法短时间内调整统计对象的刷盘策略),所以只能继续尝试第二次JVM参数调优。

统计对象堆积可能会占用比较大的内存,但这些对象是短生命周期的,很多用完就应该回收。所以第二次参数调优仍然坚持第一次的调优方向:让对象尽可能在年轻代消亡。

这次加大了年轻代的扩容力度:

1.年轻代加大到5g

2.提高晋升年龄(ajdk默认值是6,提高到最大值15)

3.加大survivor的空间使用率(ajdk默认值是50,提高到90%)

调整后的JVM参数

-server -Xms8192m -Xmx8192m -Xmn5g -XX:MaxMetaspaceSize=256m -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=15

效果

promotion fail从每天1-2次降低到0-1次,但是每次fgc停顿时间增加到了6-7秒。主要是调大的年轻代加大了old gc在重新标记阶段的扫描停顿时间。

结论

第二次调优失败。

第三次调优

在对前面两次的gc日志分析后发现,年轻代无论调多大,总会有对象在某瞬间堆积导致promotion fail,配置多大吃多大,所以加大年轻代不仅没有解决问题,反而增加了fgc时间(cms两次停顿都需要扫描年轻代)。

因此调整了调优方向:

在无法确定对象为何堆积的情况下,把fgc的时间打散,即用多次cms gc来避免fgc,减少集中停顿的时间。

需要注意的是,因为cms gc是并发gc,所以会跟用户线程抢占cpu资源。因为我们的uae容器的cpu是
8核,负载较低(1~1.5左右),cpu使用率也在1~1.5之间。cpu不是瓶颈,CMS并发对cpu资源影响不
大。

这次调优从promotion fail的产生原因,在原来参数的基础上,得出理论值公式:eden+survivor<=old*(1-阀值),计算出阀值60,为加大减少promotion fail的可能,设置为55。

调整后的JVM参数

-XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=15 -XX:CMSInitiatingOccupancyFraction=55 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpBeforeFullGC

效果

灰度一台机子,两天没有发生promotion fail,也没有发生full gc,每次cms gc时间为300到500ms。灰度扩大到所有机器,在12.8凌晨第一轮压测没有发生promotion fail,也没有发生fgc。

结论

fgc从每天1~3次减少到现在每天0次,停顿时间从每次5~7s减少到现在每次300~700ms,fgc时间过长的问题基本得到解决。问题虽然解决但仍还有可优化空间。

后续可调优空间

1、升级为G1垃圾回收器

  • ‌ 更高的内存使用率

(1)相对于CMS在多次gc后才进行内存压缩,G1在每次回收时都会进行“局部压缩”(把多个region合并为一个region)。

(2)G1垃圾回收器的eden、survivor、old区只是逻辑上的概念,物理上并没有明显的区分,一个region属于哪个分区是不确定的,这就使得G1可以通过灵活调整分区大小来达到用户设定的停顿时间。这点特别符合我们的问题场景:大部分时间对象都能在ygc时候在年轻代里消亡,只有小部分时间对象在年轻代堆积发生promotion fail。如果使用G1,大部分时间下年轻代region会占大部分,在发生对象堆积的时候,可能会动态减少年轻代region数而提高老年代region数,避免promotion fail而出现过长的fgc。

  • 可设置的停顿时间,配置简单。

  • 业务服务器8核cpu、8g的JVM内存,符合G1的硬件配置要求。

2、优化程序,根究对象在年轻代瞬间堆积的原因

虽然通过dump文件发现统计缓存对象存在大量堆积的情况,但从监控上看堆积的时间点没有明显的流量异常,需要进一步确认引起promotion fail的对象,才可能对症下药优化程序。

JVM Promotion Fail FGC问题解决相关推荐

  1. jvm YGC和FGC发生的具体场景

    1.YGC和FGC是什么 YGC:对新生代堆进行gc.频率比较高,因为大部分对象的存活寿命较短,在新生代里被回收.性能耗费较小. FGC:全堆范围的gc.默认堆空间使用到达80%(可调整)的时候会触发 ...

  2. JVM SandBox源码解析(一):启动时初始化、启动时加载模块、ModuleHttpServlet进行Http路由

    前言 上篇JVM SandBox实现原理详解文章中,主要解析了JVM SandBox的核心实现原理,并且对SandBoxClassLoader和ModuleClassLoader做了源码解析,也解释了 ...

  3. Linux网络编程中出现 listen fail : Socket operation on non-socket错误

    错误代码: int main (int argc,char *argv[]) {int lfd = 0,cfd = 0;/* 定义服务器地址结构 和 客户端地址结构*/struct sockaddr_ ...

  4. Java的ygc fgc_java基础—常用的GC策略,什么时候会触发YGC,什么时候触发FGC?

    一.内存回收策略和常见概念 常见内存回收策略可以从以下几个维度来理解: 1 串行&并行 串行:单线程执行内存回收工作.十分简单,无需考虑同步等问题,但耗时较长,不适合多cpu. 并行:多线程并 ...

  5. 干货 | 阿里巴巴HBase高可用8年抗战回忆录

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 前言 2011年毕玄和竹庄两位大神将HBase引入阿里技术 ...

  6. 阿里巴巴HBase高可用8年填坑实录

    前言 2011年毕玄和竹庄两位大神将HBase引入阿里技术体系,2014年接力棒转到东8区第一位HBase commiter天梧手中,多年来与淘宝.旺旺.菜鸟.支付宝.高德.大文娱.阿里妈妈等几乎全B ...

  7. 阿里HBase高可用8年“抗战”回忆录

    2017年开始阿里HBase走向公有云,我们有计划的在逐步将阿里内部的高可用技术提供给外部客户,目前已经上线了同城主备,将作为我们后续高可用能力发展的一个基础平台.本文分四个部分回顾阿里HBase在高 ...

  8. 阿里HBase高可用8年抗战回忆录

    前言 2011年毕玄和竹庄两位大神将HBase引入阿里技术体系,2014年接力棒转到东8区第一位HBase commiter天梧手中,多年来与淘宝.旺旺.菜鸟.支付宝.高德.大文娱.阿里妈妈等几乎全B ...

  9. Proxool 连接池销毁问题

    Proxool是常用开源连接池,最近遇到点该连接池销毁时的问题, 记录下来. 项目中使用JPA的hibernate实现, persistence.xml中hibernate配置的连接池是proxool ...

最新文章

  1. Matlab计时函数使用
  2. 【Linux 内核】调度器 ② ( sched_class 调度类结构体源码 | 源码路径 linux-5.6.18\kernel\sched\sched.h )
  3. Win服务器2008和2012哪个更好?
  4. 15年来这8门编程语言位置十分稳定,C#从低谷开始爬升
  5. 泛型集合 有序泛型 c#
  6. matlab图像处理 推荐,Matlab计算机视觉、图像处理工具箱推荐
  7. topcoder srm 708 div1 -3
  8. html5学习笔记---01.HTML5介绍,02.HTML5的新特性
  9. pytorch加载模型报错RuntimeError:Error(s) in loading state_dict for DataParallel
  10. 区块链 以太坊 合约 创建、执行 详解
  11. java编写图案1357,洛谷 P1357 花园 解题报告
  12. Spring MVC-学习笔记(5)spring MVC的文件上传、下载、拦截器
  13. HDU 6437 (费用流)
  14. 8.15游戏背包设计
  15. 『纪念册 · 转专业任务』
  16. 异常检测论文阅读《Anomaly Detection in Video Sequences: A Benchmark and Computational Model》
  17. off文件转obj文件
  18. 前端笔记 (持续更新~)
  19. 美国春季计算机硕士入学的学校,美国硕士春季入学学校推荐哪些?
  20. XSS闯关——第五关:level5

热门文章

  1. 微信新功能,屏蔽掉一些“友情群”
  2. 超级详细的 VirtualBox 虚拟机安装 及入门教程
  3. 在linux上gc日志详解,JVM CMS GC日志详解
  4. 20 个好用的 Go 语言微服务开发框架
  5. SVG_27_指尖魔法_等你施法_斗罗大陆史莱克七怪_闪亮登场
  6. SQL:结构化查询语言(Structured Query Language)。
  7. 第一类曲线、曲面积分计算公式
  8. 102美金一周获利超6倍的交易心得
  9. 启动android模拟器后,界面卡住拖不动的解决方案
  10. 浏览器,太坑的字体设置