内存分析
========
一旦有了这两个堆快照,我就使用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根的对象都将成为垃圾回收的候选对象。下面的模式对此进行了解释:
因此,如果我们的类加载器在部署后仍然处于活动状态,这意味着我们的应用程序中的某些东西正在将它“链接”到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)
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!