总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家
jmap -dump:live,file=first.bin
一旦我有了备份,我已经开始重新部署我的WAR文件7次,没有重新启动服务器。
最后,我用jmap创建了另一个堆快照。
内存分析
========
一旦有了这两个堆快照,我就使用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
最后
本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:
目录:
Java面试核心知识点
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
Java面试核心知识点