记一次性困难的GC疑问排查!

  • 电脑网络维修
  • 2024-11-15

背景

gc疑问不时是一个很难排查的疑问,但是他又是一个经常在咱们开发业务中出现的。这不,最近在我的名目中就出现了一个比拟奇葩的gc疑问,排查环节比拟繁琐,所以在这里分享一下这个整个排查环节,宿愿对大家有必定的协助

排查环节

确定GC出疑问

在某一天的上午突然出现了报警,发现是ZK断开了链接,

从图上看咱们这个失误是连续性的出现,最开局认为是zk出现了疑问,起初经过排查其余服务的zk并没有出现任何疑问。所以就疑心是外部的代码出现疑问造成的,钻研之后发现是zk出现了心跳超时状况才造成的断开链接,所以就疑心了两种状况:

假设网络有颤抖的话确实是会出现偶发性超时,但是很显著,其余一切的服务都没疑问,应该不是颤抖造成。所以机器应该是间歇性的一个卡死,普通出现这个状况首当其冲的就是咱们CPU被打满了,造成机器卡死,发现CPU并无疑问,而后就是咱们的gc带来的STW,会造成咱们的jvm进程卡顿。

观察之后确实是young gc很慢,造成咱们的JVM出现了GC卡顿,所以出现了这个现象。

排查要素

GC出现疑问普通来说两大法宝可以处置大局部疑问:

出现疑问之后我立马关上了GC日志,截图如下:

可以发现咱们的young gc曾经到达2.7s了,大家知道咱们的younggc是全程STW的,那就象征着每次gc就会卡顿2.7s,那么zk超时断开链接也就合乎反常了。再看了下这个gc搜集状况,每次也能齐全搜集。在日志中很显著在rootscanning的时期比拟长,过后对这个阶段不太相熟(前面会继续讲),所以不时也不明确为什么这样,在网上各种搜查,也没有论断。

这个时刻我在why哥群众号读到了一篇文章:倡导大家可以浏览一下这篇文章,这个文章中关键谈到了咱们jvm的一个提升,大家都知道咱们进入STW的时刻是要求一个安保点才可以的,而征询能否进入到安保点是要求消耗资源的,所以jvm在做jit提升的时刻会讲countedloop也就是计数循环提升成整个循环完结之后再进入安保点,在小米的技术文章中也提到了关系的疑问:《HBase实战:记一次性Safepoint造生长时期STW的踩坑之旅》。

看完这两个文章之后,我突然想到了咱们的代码也是counted loop的方式,所以就疑心有或许也是这个疑问造成的,马上启动代码提升,将for(int i= 0; i< n; i++) 中的int换成了long,就可以防止这种jit的提升,马上灰溜溜的将其上线,结果过了一天之后依然存在这个疑问,此时人都快解体,搞了半天原来不是这个疑问造成的。

定位疑问

关于G1之前只是看了些原理关系的,但是此时原理关系的物品如同在这里基本没啥用,所以我选择系统性的学习一下,这里我选用的是《jvmG1源码剖析和调优》这本书,在读到5.4节的时刻:

发现有两个之前没有见过的参数,一个是G1LogLevel,一个是UnlockExperimentalVMOptions,从解释说明过去看性能了之后能失掉到愈加详细的YGC日志,于是加上了这个参数而后继续观察,日志格局太长,只截取了局部日志消息,有兴味的可以上去自己打印一下:

可以发如今SystemDictionaryRoots阶段是比拟慢的,但是这个又是啥玩意呢?在书外面是没有任何引见的,于是又启动少量谷歌,终于是找到了一篇你假笨写的一篇文章:JVM源码剖析之自定义类加载器如何拉长YGC,剧烈介绍大家读完这篇文章。

好了最后我来盘一盘究竟为什么会出现gc慢的疑问呢?咱们这个定时义务是一个定时查问微信退款消息的,微信的退款消息要求解析XML,就有如下代码:

而咱们的罪魁祸首其实就在这个new XStream这个方法中,咱们的自动结构方法会调用上方的这个结构方法:

要求留意的是咱们每次创立一个XStream都会新创立一个ClassLoader,先解释一下ClassLoader,这里间接援用你假笨的一段话:

这里着关键说的两个概念是初始类加载器和定义类加载器。举个栗子说吧,AClassLoader->BClassLoader->CClassLoader,示意AClassLoader在加载类的时刻会委托BClassLoader类加载器来加载,BClassLoader加载类的时刻会委托CClassLoader来加载,假设咱们经常使用AClassLoader来加载X这个类,而X这个类最终是被CClassLoader来加载的,那么咱们称CClassLoader为X类的定义类加载器,而AClassLoader为X类的初始类加载器,JVM在加载某个类的时刻对AClassLoader和CClassLoader启动记载,记载的数据结构是一个叫做SystemDictionary的hashtable,其key是依据ClassLoader对象和类名算进去的hash值(其实是一个entry,可以依据这个hash值找到详细的index位置,而后构建一个蕴含kalssName和classloader对象的entry放到map里),而value是真正的由定义类加载器加载的Klass对象,由于初始类加载器和定义类加载器是不同的classloader,因此算进去的hash值也是不同的,因此在SystemDictionary里会有多项值的value都是指向同一个Klass对象。

咱们把这个放到咱们的场景来看就是上方这个状况:

由于咱们每次恳求都会新创立一个Xstream对象,从而也会新创立一个ClassLoader,由于咱们的ClassLoader的key是依据每个对象来算进去的hash值,假设每次都新创立,人造hash值不一样,从而造成咱们有很多ClassLoader指向XStream这个class。为什么SystemDictionary的大小会影响咱们GC时期呢?

构想一下这么个状况,咱们加载了一个类,而后构建了一个对象(这个对象在eden里构建)当一个属性设置到这个类(static变量)里,假设gc出现的时刻,这个对象是不是要被找进去标活才行,那么人造而然咱们加载的类必需是咱们一项关键的gcroot,这样SystemDictionary就成为了gc环节中的被扫描对象了。

咱们的class消息是被调配在哪里的呢?在java7的话是在终身代,在java8就到来了元数据空间也就是咱们的堆上,所以咱们的younggc的时刻是不会回收咱们的class消息的,那么咱们怎样处置这个疑问呢?

但是咱们这个疑问不应该经过渣滓搜集去处置,而是应该从根源上去处置,那就是不能经常使用自动的XStream结构函数,而是要求经常使用固定ClassLoader的结构函数。

经过修正之后上线,经过观察,没有出现慢GC的现象。

最后

经过这次排查的阅从来看,遇到GC疑问尤其是那种比拟不经常出现的,真的是十分难搞,你或许要求对这个疑问启动系统的学习,以及少量的查找资料能力找到要素,我在排查这个疑问的时刻掉了不少头发。在这里记载一下这个阅历,宿愿对大家的一些排查能有协助。

  • 关注微信

本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载联系作者并注明出处:https://duobeib.com/diannaowangluoweixiu/9093.html

猜你喜欢

热门标签

洗手盆如何疏浚梗塞 洗手盆为何梗塞 iPhone提价霸占4G市场等于原价8折 明码箱怎样设置明码锁 苏泊尔电饭锅保修多久 长城画龙G8253YN彩电输入指令画面变暗疑问检修 彩星彩电解除童锁方法大全 三星笔记本培修点上海 液晶显示器花屏培修视频 燃气热水器不热水要素 热水器不上班经常出现3种处置方法 无氟空调跟有氟空调有什么区别 norltz燃气热水器售后电话 大连站和大连北站哪个离周水子机场近 热水器显示屏亮显示温度不加热 铁猫牌保险箱高效开锁技巧 科技助力安保无忧 创维8R80 汽修 a1265和c3182是什么管 为什么电热水器不能即热 标致空调为什么不冷 神舟培修笔记本培修 dell1420内存更新 青岛自来水公司培修热线电话 包头美的洗衣机全国各市售后服务预定热线号码2024年修缮点降级 创维42k08rd更新 空调为什么运转异响 热水器为何会漏水 该如何处置 什么是可以自己处置的 重庆华帝售后电话 波轮洗衣机荡涤价格 鼎新热水器 留意了!不是水平疑问! 马桶产生了这5个现象 方便 极速 邢台空调移机电话上门服务 扬子空调缺点代码e4是什么疑问 宏基4736zG可以装置W11吗 奥克斯空调培修官方 为什么突然空调滴水很多 乐视s40air刷机包 未联络视的提高方向 官网培修 格力空调售后电话 皇明太阳能电话 看尚X55液晶电视进入工厂形式和软件更新方法 燃气热水器缺点代码

热门资讯

关注我们

微信公众号