首页 > 其他分享 >JVM系统优化实践(16):线上GC案例

JVM系统优化实践(16):线上GC案例

时间:2023-04-18 17:32:18浏览次数:41  
标签:触发 Full 系统优化 16 对象 XX GC JVM

您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~




列举几个实际使用案例说一下GC的问题。一个高峰期每秒10万QPS的社交APP,个人主页模块是流量最大的那个,而一次个人主页的查询,大概会加载5M的数据。

由于并发量太高,导致高峰期年轻代的Eden区被迅速填满,且频繁触发Young GC,每次Young GC后存活对象较多,Survivor中放不下。大量的对象快速进入老年代,由于老年代满而频繁触发Full GC。

优化JVM参数为:

-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5

CMS会导致大量的内存碎片,可以在5次GC之后,做一次Compaction压缩操作。

所以,在Full GC频率升高时,需要将如上参数调整为:

-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

避免越来越频繁的GC。


一般新手工程师在部署生产环境时基本不会对JVM进行设置,基本跟上也都是使用JVM的默认设置,这是一个很大的隐患。例如,如果不设置-Xmx或者-Xms的话,可能初始的年轻代和老年代就几百M大小。Full GC一般在正常情况下,都是按天为单位来发生的,比如每天一次,或几天一次Full GC。

下面是一个公司级别的JVM模板:

JVM系统优化实践(16):线上GC案例_软引用


Full GC不仅会因为老年代占满而触发,也会因为Metaspace区域被占满而触发。Java中的反射会将产生的类放在Metaspace中,而SoftReference软引用对象的回收公式是:

1、clock - timestamp ≤ freespace * SoftRefLRUPolicyMSPerMB;

2、clock – timestamp:表示软引用对象多久没被访问过;

3、freespace:JVM的空闲内存空间;

4、SoftRefLRUPolicyMSPerMB:每一MB空闲空间允许SoftReference对象存活多久。

5、如果freespace=3000MB,SoftReference=1000毫秒,则软引用对象可以存活freespace * SoftReference = 3000秒 = 50分钟。

如果-XX:SoftRefLRUPolicyMSPerMB=0,会导致可能刚创建出来的反射类迅速被Young GC回收掉。程序执行会继续执行反射以弥补不足,如此反复循环,造成Metaspace被占满。一般可将SoftRefLRUPolicyMSPerMB设为1000~5000毫秒,让JVM创建的软引用不会被立即回收,Metaspace的占用是比较稳定的,不会大幅波动,因为没有必要专门设置SoftRefLRUPolicyMSPerMB这个值。


通常,一个比较良好的JVM性能,应该是Full GC几天才触发一次,或者最多一天几次而已。未优化前的JVM参数:

-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=5 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFractinotallow=68 -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC

导致的结果是:

1、6天内,Young GC总次数2.6万次,总耗时1400秒

2、6天内,Full GC总次数250次,总耗时70秒

可以看出:

1、老年代1024M,年轻代512M,且Eden:S0:S1 = 5:1:1

2、-XX:CMSInitiatingOccupancyFractinotallow=68,即老年代空间达到680M时触发Full GC

可由上述GC日志倒推JVM的内存模型:

JVM系统优化实践(16):线上GC案例_软引用_02


每分钟3次Young GC,说明每20秒会让Eden满,则每秒产生365/20 ≈ 15~20M对象:

JVM系统优化实践(16):线上GC案例_老年代_03


每30分钟1次Full GC,说明每30分钟可能产生680M对象,或者每次Young GC后存活对象太多,老年代放不下年轻代转过来的对象:

JVM系统优化实践(16):线上GC案例_JVM_04


通过jstat得知:每次Young GC后,升入老年代的对象很少,因为S0/S1太小,经常触发动态年龄判定规则:

JVM系统优化实践(16):线上GC案例_软引用_05


再次通过jstat得知:老年代总会突然有几百M对象占据着:

JVM系统优化实践(16):线上GC案例_JVM_06


因此,答案很明显:大对象。一定是系统运行时,突然产生几百M大对象,而年轻代放不下这些大对象,它们就直接进入老年代,频繁触发Full GC:

JVM系统优化实践(16):线上GC案例_软引用_07


然后再定位产生大对象的原因:

1、通过jmap,导出一份dump内存快照,接着用jhat或者Visual VM之类的工具分析dump文件;

2、通过分析dump,得知那个几百M的大对象,是从数据库中查出的数据,存放在Map中;

3、进一步排查出问题SQL语句。


故障解决和优化:

1、首先要解决代码中的bug;

2、年轻代明显太小,S0/S1区太小,因此需要调整JVM参数为:

-Xms1536M -Xmx1536M -Xmn1024M -Xss256K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=5 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFractinotallow=92 -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC


通过查看jstat,发现每秒都有Full GC,每次几百毫秒,年轻代增长不快,老年代才使用10%空间,元空间也才20%。怀疑人为原因:代码中写了System.gc()!

System.gc()不能随便写,它让JVM执行一次全空间的Full GC!

在系统负载量低时,这段代码可能没什么问题,但当系统负载量很高时,这段代码会频繁触发Full GC,导致系统直接卡死!为预防此类问题,可以通过加入-XX:+DisableExplicitGC避免显示触发GC。




感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

标签:触发,Full,系统优化,16,对象,XX,GC,JVM
From: https://blog.51cto.com/u_15817148/6196440

相关文章

  • 未来十年,与人工智能争夺生存机会的16个实用技巧
    如今,许多公司都已经开始利用人工智能和机器学习,并且这些技术的影响只会越来越大。虽然这对于想要提高业绩的企业来说是件好事,但许多员工也担心机器人会在未来几年内取代他们的工作。在未来和AI争夺工作的16个实用技巧虽然人工智能可能会改变某些类型的工作,但它们永远不会完全取代人......
  • [AGC061D] Almost Multiplication Table
    人类智慧。答案显然具有可二分性,考虑如何check。我们使用调整法,不妨设\(x_n<y_m\)(反着做同理),一开始我们令\(x_i=1,y_i=+\infty\)。每次我们期望让\(x\)不断变大,\(y\)不断变小,不断将它们调整到当前的上下界。具体的,每次令\(x_i=\max\{x_i,\max\lceil{a_{i,j}-k\overy......
  • DG搭建报错 ORA-16047: DGID mismatch between destination setting and target datab
    最近有需求要给数据库新搭一个DG变为一主两从,搭好之后测试发现一直没有同步,检查问题。从库一直等待接收71855号日志主库有归档日志发送失败的报错,可以看到归档到dest_2(原从库)是成功的,而到desc_3(新从库)则是失败的根据日志提示查看arc2进程的trace日志看到有ora-16058和ora-16047的报......
  • 【2023-04-16】连岳摘抄
    23:59中国哲学儒、墨、道、法各家,传承数千年而蕴涵着中国文化的内涵,各有其普世的价值。这种普世价值,是指在人文精神的照耀下,老、孔、墨、庄的思想多散发出普世的情怀,即老子的贵柔及其宽容心态、孔子的恕道及其家庭伦理、墨子的兼爱与非攻思想、庄子的艺术人生和齐物精神。  ......
  • GCC相关
    GCC,theGNUCompilerCollection  https://gcc.gnu.org/ GCC:Anonymousread-onlyGitaccess  https://gcc.gnu.org/git.html browseourGithistoryonline https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git......
  • 锂电池3.7V升5V/5A内置MOS大电流升压IC型号推荐FS2116B
    电源电路是电子产品中必不可少的部分。然而不同的器件或者模块工作电压不一样,所以DC-DC电压转换电路应用中十分常见。例如便携式电子产品,一般都内置电池,如果是单节锂电3.7V供电,通过DC-DC升压电路,从3.7V升压到5V、8V、9V、12V等再给其他电路供电。升压电路属于开关型电路,最关心的就......
  • Robotruck UVA - 1169
    有n个垃圾,第i个垃圾的坐标为(xi,yi),重量为wi。有一个机器人,要按照编号从小到大的顺序捡起所有垃圾并扔进垃圾桶(垃圾桶在原点(0,0))。机器人可以捡起几个垃圾以后一起扔掉,但任何时候其手中的垃圾总重量不能超过最大载重C。两点间的行走距离为曼哈顿距离(即横坐标之差的绝对值加上纵......
  • 4月16日leetcode二叉树前序遍历创建字符串,二叉树的层序遍历
    给你二叉树的根节点root,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。空节点使用一对空括号对"()"表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。来源:力扣(LeetCode)链接:https://leetcode.cn/pro......
  • 16进制转10进制
            ......
  • CF1646E Power Board 题解
    题目链接:https://codeforces.com/contest/1646/problem/E题目大意:有一个\(n\timesm\)的矩阵,其中第\(i\)行第\(j\)列的格子中的数字是\(i^j\)。问:矩阵中存在多少个不同的数?解题思路:可以很明显地发现,第\(1\)行的数字全部都是\(1\),而且在其它行不会出现数值为\(1\)......