Metaspace 引起的 FullGC 问题排查过程及解决方案
点击蓝色“程序猿DD”关注我哟
加个“星标”,不忘签到哦
转载自公众号:字节观
关注我,回复口令获取可获取独家整理的学习资料:
- 001 :领取《Spring Boot基础教程》
- 002 :领取《Spring Cloud基础教程》
最近新上线的系统偶尔会报FullGC时间过长(>1s)的告警,查看GC日志,如下图所示:
看到GC日志,我第一时间关注到的不是GC耗时,而是GC触发的原因:Metadata GC Threshold。也就是FullGC触发的原因是因为Metaspace大小达到了GC阈值。在监控系统里面看了一下Metaspace的大小变化趋势,如下图所示:
按照以往的经验,Metaspace在系统稳定运行一段时间后占用空间应该比较稳定才对,但是从上图来看,Metaspace显然是呈现大幅波动。为什么呢?
相关知识
我们知道Metaspace主要存储类的元数据,比如我们加载了一个类,那么这个类的信息就会按照一定的数据结构存储在Metaspace中。Metaspace的大小和加载类的数目有很大关系,加载的类越多,Metaspace占用内存也就越大。
Metaspace被分配于堆外空间,默认最大空间只受限于系统物理内存。跟它相关的比较重要的两个JVM参数:
-XX:MetaspaceSize -XX:MaxMetaspaceSize。
MaxMetaspaceSize大家从名字也能猜到是指Metaspace最大值,而MetaspaceSize可能就比较容易让人误解为是Metaspace的最小值,其实它是指Metaspace扩容时触发FullGC的初始化阈值,在GC后该值会被动态调整:如果本次GC释放了大量空间,那么就适当降低该值,如果释放的空间较小则适当提高该值,当然它的值不会大于MaxMetaspaceSize.
另外一个相关知识是:Metaspace中的类需要满足什么条件才能够被当成垃圾被卸载回收?条件还是比较严苛的,需同时满足如下三个条件的类才会被卸载:
1、该类所有的实例都已经被回收;
2、加载该类的ClassLoader已经被回收;
3、该类对应的java.lang.Class对象没有任何地方被引用。
排查过程
我们可以回过头再细看GC日志,可以看出Metaspace已使用内存在FullGC后明显变小(372620K -> 158348K),说明Metaspace经过FGC后卸载了很多类。从这点来看,我们有理由怀疑系统可能在频繁地生成大量”一次性“的类,导致Metaspace所占用空间不断增长,增长到GC阈值后触发FGC。
那么这些被回收的类是什么呢?为了弄清楚这点,我增加了如下两个JVM启动参数来观察类的加载、卸载信息:
-XX:TraceClassLoading -XX:TraceClassUnloading
加了这两个参数后,系统跑了一段时间,从Tomcat的catalina.out日志中发现大量如下的日志:
到此基本可以确定Metaspace增长的元凶是这些类,那么这些类sun.reflect.GeneratedSerializationConstructorAccessorXXX是干嘛的呢?又是从哪里引进来的呢?我也是一脸懵逼~~
根据类名Google了一把,找到了@寒泉子写的《从一起GC血案谈到反射原理》,这篇文章对这些类的来源解释得很透彻。在这里我简单总结如下:
Method method = XXX.class.getDeclaredMethod(xx,xx);
method.invoke(target,params);
这些类的来源是来自反射,类似上面所示的反射代码应该大家都写过或者看过,我们常用的大多数框架比如Spring、Dubbo等都大量使用反射。出于性能的考虑,JVM会在反射代码执行一定次数后,通过动态生成一些类来将”反射调用”变为“非反射调用”,以达到性能更好。而这些动态生成的类的实例是通过软引用SoftReference来引用的。
我们知道,一个对象只有软引用SoftReference,如果内存空间不足,就会回收这些对象的内存;如果内存空间足够,垃圾回收器不会回收它。只要垃圾回收器没有回收它,该对象就可以被使用。那么究竟在什么时候会被回收呢?
SoftReference中有一个全局变量clock代表最后一次GC的时间点,有一个属性timestamp,每次访问SoftReference时,会将timestamp其设置为clock值。
当GC发生时,以下几个因素影响SoftReference引用的对象是否被回收:
1、SoftReference对象实例多久未访问,通过clock - timestamp得出对象大概有多久未访问;
2、内存空闲空间的大小;
3、SoftRefLRUPolicyMSPerMB常量值;
是否保留SoftReference引用对象的判断参考表达式,true为不回收,false为回收:
clock - timestamp <= freespace * SoftRefLRUPolicyMSPerMB
说明:
clock - timestamp:最后一次GC时间和SoftReference对象实例timestamp的属性的差。就是这个SoftReference引用对象大概有多久未访问过了。
freespace:JVMHeap中空闲空间大小,单位为MB。
SoftRefLRUPolicyMSPerMB:每1M空闲空间可保持的SoftReference对象生存的时长(单位ms)。这个参数就是一个常量,默认值1000,可以通过参数:-XX:SoftRefLRUPolicyMSPerMB进行设置。
查看了一下我们系统的JVM参数配置,发现我们把SoftRefLRUPolicyMSPerMB设置为0了,这样就导致软引用对象很快就被回收了。进而导致需要频繁重新生成这些动态类。
为了验证这个猜测,我把SoftRefLRUPolicyMSPerMB改成了6000进行观察,发现果然猜得没错。系统启动后不久Metaspace的使用空间基本保持不变了,运行几天后也没再出现因为Metaspace大小达到阈值而触发FGC。至此问题解决。
References
[1] 假笨说-从一起GC血案谈到反射原理: https://mp.weixin.qq.com/s/5H6UHcP6kvR2X5hTj_SBjA?
[2] Java的强引用,软引用,弱引用,虚引用及其使用场景: http://blogxin.cn/2017/09/16/java-reference/
推荐阅读:
MySQL跑在CentOS 6 和 7上的性能比较
Spring Boot 配置文件中的花样,看这一篇足矣!
Mybatis的工作原理,你了解过吗?
理解 IntelliJ IDEA 的项目配置和Web部署
如何告别那些没卵用的线上告警!
活动介绍:自律到极致-人生才精致:第8期
活动奖励:《小灰的算法之旅》* 10
扫描下面二维码签到参与
关注我,加个星标,不忘签到哦~
2019
与大家聊聊技术人的斜杠生活
Metaspace 引起的 FullGC 问题排查过程及解决方案相关推荐
- 一次堆外OOM问题的排查过程
转载自 一次堆外OOM问题的排查过程 背景 线上服务有一台机器访问不通(一个管理平台),在公司的服务治理平台上查看服务的状况是正常的,说明进程还在.进程并没有完全crash掉.去线上查看机器日志, ...
- 内存很空却频繁gc_记一次不太成功的频繁 full gc 排查过程
上周自己负责的一个应用出现频繁full gc的问题,不得不尝试优化一下.第一次做这种事只能先看看网上的文章,然后亲自尝试怎么去完成减少full gc的频率,降低young gc的频率这一目标.虽然最终 ...
- 一次线上服务fullGC原因排查
2017年12月09日 21:39:46 阅读数:384 一.现象 早上九点多又收到了fullGC次数过高的应用监控告警{P1}{故障}JVM Old GC all(#3) full_gc_count ...
- java gc full gc_记一次Java服务频繁Full GC的排查过程
现象 从监控来看,堆内存是够用的,但是频繁触发Full GC,每秒钟三次,每次耗时三四秒. image.png 结合Young GC的信息和堆内存的使用情况,可以发现新生代的内存够用,老生代的内存不够 ...
- java cms cpu占用率_cpu使用率过高和jvm old占用过高排查过程
今天断断续续的收到管理平台的异常报警,cpu占用过高和jvm old占用过高,这个时候赶紧去排查原因,下面记录了我的排查过程,可能里面还有不正确的地方,欢迎各位大佬指正,也欢迎大家关于类似的案例一起交 ...
- 实战派:一次kafka卡顿事故排查过程!
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 等你归去来 来源 | www.cnblogs. ...
- 干货!一次kafka卡顿事故排查过程
由于一次功能上线后,导致某数据量急剧下滑,给我们紧张的呢!排查过程也是个学习过程!抛开结果,方法论可供参考- 1. 确认问题的真实性? 被数据部门告知,某数据量下滑严重,当时即知道问题的严重性.且该问 ...
- 多队列 部分队列没有包_记一次TCP全队列溢出问题排查过程
简介:记一次TCP全队列溢出问题排查过程 1. 前言 本文排查的问题是经典的TCP队列溢出问题,因TCP队列问题在操作系统层面没有明显的指标异常,容易被忽略,故把排查过程分享给大家. 2. 问题描述 ...
- 一次堆外内存泄露的排查过程
转载自 一次堆外内存泄露的排查过程 最近在做一个基于 websocket 的长连中间件,服务端使用实现了 socket.io 协议(基于websocket协议,提供长轮询降级能力) 的 netty- ...
最新文章
- oracle hot patch david,Oracle EBS使用adpatch工具打patch过程(hotpatch mode)
- 6月第1周回顾:华为再现猝死 中国成全球最大宽带市场
- 皮一皮:可怜的西瓜...
- python【蓝桥杯vip练习题库】BASIC-18 矩形面积交(线段交)
- 在VS.NET2003中无法新建C#项
- 程序员面试题精选100题(02)-设计包含min函数的栈[数据结构]
- 【Android开发】线程与消息处理-Handler消息传递机制之Looper
- 吴恩达机器学习 逻辑回归 作业2(芯片预测) Python实现 代码详细解释
- 若依框架如何进行单元测试
- 考研复习计划怎么做?MindManager来帮你!
- 30页不容错过的超赞项目管理PPT
- HDU - 4567 Brilliant Programmers Show 2013长沙邀请赛
- 学习信号量 sem_init、sem_destroy、sem_post、sem_wait、sem_trywait、sem_getvalue
- 卜算子.咏梅 英文版
- 用VS2005打开方案出现“此安装不支持该项目类型
- 快速搭建仓储管理系统
- 地方征信平台第2讲:河北省征信
- PIC 1508 TIM1的定时器中断使用
- linux p4使用心得
- 基于python和opencv的图像分割旋转裁剪