美文网首页
jdk11-zgc-gc时间不断增长

jdk11-zgc-gc时间不断增长

作者: 一天的 | 来源:发表于2022-01-26 20:37 被阅读0次

1.现象

为了降低gc时间,我们打算对一批服务安装jdk11,使用zgc。在对zgc进行测试期间,发现随着程序的运行,gc时间越来越长。如下图所示:

每分钟gc总耗时

同时进程的gc次数并没有发生太大变化,如下图所示:

每分钟gc总次数

zgc的 gc.time 只和 GC Roots 相关,关于zgc可以参考:https://tech.meituan.com/2020/08/06/new-zgc-practice-in-meituan.html

既然gc次数没有变多,所以应该是GC Roots 数量增长

2.原因分析

我们去查看近几天的gc日志,会发现 Subphase: Pause Roots ClassLoaderDataGraph  这个阶段的耗时会不断增加

gc日志

这时候开始怀疑GC Roots有问题

此时查看metaspace元空间监控,发现metaspace不断增长,metaspace里的对象是被认为GC Roots。所以因为metaspace不断增长,导致GC Roots越来越多,最终导致gc时间越来越长

元空间内存占用情况

为什么metasapce空间不断增长呢?

metaspace空间主要保存对象类信息,我们查看关于class相关监控信息

加载class信息监控

可以看到我们程序不断load class,但是没有unload class,所以导致meta内存一直增长

原因大概也就清楚了,但是此时产生疑问,为什么程序原先使用jdk8 cms gc算法,没有这个问题呢。

我们查看一下之前使用cms算法相关监控

cms机器监控信息

可以看到这台 cms 机器,也不断load class,但是他也会 unload class,所以metaspace一直维持平稳

因为我们在使用cms时,设置了一个jvm参数:CMSClassUnloadingEnabled 。该参数表示在进行cms,进行class卸载

3. zgc

为什么zgc不会收 meta:使用的jdk11不支持回收,jdk12才支持

在JDK11,zgc垃圾回收器目前还只是实验性的功能,只支持Linux/x64平台。后续优化接改进,短时间内无法更新到JDK11中,所以可能会遇到一些不稳定因素。例如: 1. JDK12支持并发类卸载功能。2. JDK13将可回收内存从4TB支持到16TB。3. JDK14提升稳定性的同时,提高性能。4. JDK15从实验特性转变为可生产特性 。所以对于一些大量使用反射、动态代理、CGLIB和Javasist等频繁自定义类加载器的场景中,ZGC难以处理Metaspace的巨大内存压力。

4.为什么metaspace一直升高

我们对运行的进程进行class统计

jcmd {pid} GC.class_stats

加载的class类信息

发现存在大量的jdk.internal.reflect.GeneratedConstructorAccessor class类

我们对上述的内容进行前缀统计,命令如下:

 jcmd {pid} GC.class_stats |awk '{print$13}'|sed  's/\(.*\)\.\(.*\)/\1/g'|sort |uniq -c|sort -nrk1

class前缀统计

发现 jdk.internal.reflect 包名下的类文件,占用了很大一部分,并且随着程序运行,jdk.internal.reflect这个类文件越来越多。

这个就是我们在使用jdk反射时,会自动生成的类字节码,被jvm加载进metaspace。随着程序运行,加载类字节码越来越多,但是没有释放,导致meta越来越大。

5.解决办法

-Dsun.reflect.inflationThreshold 可以控制通过反射生成字节码。(该值表示 反射调用多少次 才开始生成字节码)

当把该参数这是int 最大值时,说明永不生成字节码。

从stackoverflows摘抄一段话

When using Java reflection, the JVM has two methods of accessing the information on the class being reflected. It can use a JNI accessor, or a Java bytecode accessor. If it uses a Java bytecode accessor, then it needs to have its own Java class and classloader (sun/reflect/GeneratedMethodAccessor class and sun/reflect/DelegatingClassLoader). Theses classes and classloaders use native memory. The accessor bytecode can also get JIT compiled, which will increase the native memory use even more. If Java reflection is used frequently, this can add up to a significant amount of native memory use. The JVM will use the JNI accessor first, then after some number of accesses on the same class, will change to use the Java bytecode accessor. This is called inflation, when the JVM changes from the JNI accessor to the bytecode accessor. Fortunately, we can control this with a Java property. The sun.reflect.inflationThreshold property tells the JVM what number of times to use the JNI accessor. If it is set to 0, then the JNI accessors are always used. Since the bytecode accessors use more native memory than the JNI ones, if we are seeing a lot of Java reflection, we will want to use the JNI accessors. To do this, we just need to set the inflationThreshold property to zero.

If you are on a Oracle JVM then you would only need to set:  -Dsun.reflect.inflationThreshold=2147483647

If you are on IBM JVM, then you would need to set:   -Dsun.reflect.inflationThreshold=0

大概意思说:使用java反射,内部实现有2种方式,一种是jni,另一种是生成字节码方式。生成字节码方式会占用更多内存,但是性能会好一点。sun.reflect.inflationThreshold 代表,反射执行多少次后,开始使用字节码方式,当我们把这个参数设置为int最大值,代表永不使用字节码方式,也就没有内存问题了。

具体原理参考:

https://www.moregeek.xyz/i/880000804235

https://stackoverflow.com/questions/16130292/java-lang-outofmemoryerror-permgen-space-java-reflection

重新加上 -Dsun.reflect.inflationThreshold=2147483647 这个参数,后来gc.time 次数就一直稳定下来了,并且metaspace空间也不增长了

相关文章

  • jdk11-zgc-gc时间不断增长

    1.现象 为了降低gc时间,我们打算对一批服务安装jdk11,使用zgc。在对zgc进行测试期间,发现随着程序的运...

  • 你还记得她们吗?

    随着时间的不断增长,记忆的长度也不断在增加,虽然偶尔也会被自己的大脑所抛弃,但丝毫不影响长度的增长。 今天晚上,本...

  • 复利的魔力

    复利是什么? 复利就是随着时间的推移,数值会不断增大,时间越长,,增长速度越快 复利就像一把能开启爆发式增长的钥匙...

  • 记录当下,活出青春

    常言道,见字如人! 从小到大,随着时间,字体在不断的改变,如同人一般,通过时间不断增长、不断改变!但不变的是初心,...

  • 冥想与修行给我生活带来的改变

    随着年龄增长,自己的烦恼在不断增长,自己的欲望在不断增长,而生活不顺心十之八九,两者在不断抗衡,极大消耗我的能量,...

  • 皱纹

    都说时间如流水,岁月不饶人,一点不假,而随着时间的流逝,除了不断增长的年龄,外貌也跟着不断变化,总让人有种少壮...

  • 时间和健康

    时间和健康是最重要的。我开始意识到这个的时候,已经是三十岁了。 时间在不断流逝,年岁不断在增长,父母在...

  • 离别车站

    车站,有史以来都是离别的象征。 随着年龄的增长,离别在不断地上演,离别时间也在渐渐地增长,从一个星期,到...

  • 解决spark streaming长时间运行日志不断增长问题

    解决spark streaming长时间运行日志不断增长问题一、spark streaming log 日志二、s...

  • 解决spark streaming长时间运行日志不断增长问题

    @[TOC](解决spark streaming长时间运行日志不断增长问题)组件:基于CDH5.13、spark2...

网友评论

      本文标题:jdk11-zgc-gc时间不断增长

      本文链接:https://www.haomeiwen.com/subject/yvxghrtx.html