【问题标题】:Metaspace growth, dead classloader and GC元空间增长、死类加载器和 GC
【发布时间】:2021-02-24 20:19:23
【问题描述】:

我们有一种情况,springboot 微服务的元空间不断增长,但堆表现良好。

jmap -clstats 显示有数千个以下类型的死类加载器。

0x00000000e3c8e3c8 1 4087 0x00000000e0004d18 dead com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x000000010087c7e8

在最初的高水位 GC 被触发,我看到元空间下降。在由于定义的元空间大小而触发的强制 GC 之后,我看到元空间不断增长,并且我看到更多相同类型的死类加载器被保留在元空间中。我确实看到了一些 GC 活动,但元空间消耗没有下降。但是,如果我通过 visualvm 强制 GC 收集,则会卸载大量类,并且元空间消耗会回到服务启动时的状态。

为什么 JVM 管理的 GC 不会卸载这些死掉的类加载器,而强制 GC 会呢?如果弱/软/幻像引用是原因,那么这不应该也适用于强制 GC 吗?

这是在 Java8 上的。任何人都可以就我接下来应该看的地方给出一些指示吗?显然有泄漏,有没有办法知道 TemplatesImpl$TransletClassLoader 的父类加载器?

感谢任何帮助。

【问题讨论】:

标签: java java-8 memory-leaks garbage-collection metaspace


【解决方案1】:

首先,JVM 只会在 Full GC 期间清除 Metaspace,而不会在 Young GC 期间清除。所以你看到的行为是预期的。

在最初的高水位 GC 被触发,我看到元空间下降。

如果您检查 GC 跟踪,您将看到 System.GC() 调用。这就是 Full GC。

但是,如果我通过 visualvm 强制进行 GC 收集,则会卸载大量类,并且元空间消耗会回到服务启动时的状态。

同样,这将是由 visualvm 触发的 Full GC,可以在 GC 跟踪中看到。这就是您看到利用率下降的原因。

根据您提供的描述,我认为您没有类加载器泄漏,因为在 Full GC 期间所有内容都被清理了。根据我的经验,如果应用程序不必要地保持某些对象处于活动状态,因此即使在 Full GC 期间也不会被垃圾收集,我只会将其视为“内存泄漏”。在您的情况下,我建议使用 -XX:MaxMetaspaceSize 标志来限制元空间大小。当占用率达到该阈值时,JVM 将自动触发 Full GC,正如您所注意到的,元空间使用率将下降。明智地设置该限制,因为太低的值会导致java.lang.OutOfMemoryError: Metaspace 问题。

有关元空间的更多详细信息可以找到here

【讨论】:

  • 您能帮我检查一下我的问题吗?类加载器已死,可以通过 visualvm click 重新校准。但是,如果我不通过 visualvm 触发 gc,它就会失败。 stackoverflow.com/questions/67133935/…
猜你喜欢
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多