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,从而防止我们的整个类加载器也成为它。 我们找到凶手了!

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618164986)

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值