ClassLoader和内存泄漏:一个Java爱情故事

一旦有了这两个堆快照,我就使用Eclipse内存分析器MAT来读取dump文件。以下是我发现的:

Size: 85.3 MB Classes: 23.5k Objects: 1.9m Class Loader: 436

消耗了853 MB。我个人认为这是一个可以接受的应用程序。让我们进入第二个GC:

Size: 271.9 MB Classes: 35k Objects: 7.1m Class Loader: 1.4k

我们可以看出有一个明显的问题。7次部署后,内存消耗增加了两倍。某处有明显的内存泄漏。是时候采取行动了。

了解内存泄漏问题所在

==============

既然我确信内存泄漏了,我已经使用jmap来查看内存细节,了解是什么消耗了这么多内存。结果令人惊讶:

371 instances of “*ClassLoader”, loaded by “jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x7e021a658” occupy 198,789,800 (??.??%) bytes.

Biggest instances:

  • ClassLoader @ 0x7ef531c30 - 27,782,296 (9.74%) bytes.

  • ClassLoader @ 0x7ee056470 - 27,781,552 (9.74%) bytes.

  • ClassLoader @ 0x7e6658b18 - 27,781,208 (9.74%) bytes.

  • ClassLoader @ 0x7ec60ab60 - 27,780,856 (9.74%) bytes.

  • ClassLoader @ 0x7ef531cd8 - 27,780,032 (9.74%) bytes.

  • ClassLoader @ 0x7ea3074b8 - 27,779,608 (9.74%) bytes.

  • ClassLoader @ 0x7e31b53b0 - 27,200,584 (9.54%) byte

如您所见,内存中有很多类装入器。最大的实例是以前部署的实例。它们还没有被GC清理干净,这就解释了内存泄漏的原因: 有些东西使这些实例以及它们包含的所有数据保持了活动状态。

在Java中GC是如何工作的

==================

在搜索内存泄漏的原因之前,了解Java垃圾回收的工作原理非常重要。使用的算法称为标记和扫描。简而言之,它是如何工作的:

在Java中,有一些特殊的对象不能在应用程序运行时被垃圾回收。这些对象称为GC根。例如,actives线程、主类中的静态变量、系统类装入器、系统类等…

因此,算法是这样进行的:它将从GC根开始构建一种树,并尝试通过引用它们的用法来确定每个活动对象的路径。当算法完成时,所有未连接到GC根的对象都将成为垃圾回收的候选对象。下面的模式对此进行了解释:

ClassLoader和内存泄漏:一个Java爱情故事

因此,如果我们的类加载器在部署后仍然处于活动状态,这意味着我们的应用程序中的某些东西正在将它“链接”到GC根,从而阻止任何垃圾收集。现在我知道该找什么了。

追踪内存泄漏问题

============

Eclipse内存分析器有一个非常有用的函数,名为“path to GC roots”,它显示了是什么使特定的类保持活动状态。以下是我发现的:

  • ClassLoader @ 0x7ee056470

    • contextClassLoader io.github.classgraph.ScanResult$1
      • […]
        • hooks java.lang.ApplicationShutdownHooks @ 0x7e00863b8 (System class)

如你所见,可疑库在内部使用类图库在类装入器上执行一些操作。这个 ClassGraph 库在 ApplicationShutdownHooks 类(这是一个系统类,因此是一个GC根)上注册了一个 shutdownhook 。 ApplicationShutdownHooks 用于注册在JVM关闭时要执行的特殊代码,由于我们的JVM在我们的情况下没有重新启动(请记住,我们是在不重新启动的情况下进行部署的),所以钩子永远不会被调用,因此仍然是活动的,保持对 ScanResult 对象的引用,防止它成为GC,从而防止我们的整个类加载器也成为它。 我们找到凶手了!

希望ClassGraph是开源的,所以我查找了报告的问题,发现了一些有趣的东西。

已经有人报告了这个bug,它在4.8.51版本中得到了解决。但是这个bug仍然存在,我已经查看了可疑的库源代码,你猜怎么着?他们使用的是4.6.32。bug还在那里。

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

了解详情https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB
24063645128)]

[外链图片转存中…(img-w6PVFnRv-1724063645128)]

[外链图片转存中…(img-fZkOSCNQ-1724063645129)]

了解详情https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值