如何使用MAT理解类加载器泄漏以及如何避免它们

好吧,这将是一个很长的问题(我想问很多相关的问题,我觉得卡住了!)。 我花了很多时间试图弄清楚某些事情,但我无法自信地得出结论。 我是性能分析/堆分析的新手,我要求初学者帮助深入研究这些领域。 我发现很难理解这些概念,并按照方法弄清楚事情……

我们面临的问题是,经过几个小时的执行,我们的应用程序响应时间增加,执行变得如此缓慢,使应用程序停止运行! 我还分析了线程转储,我不敢说没有从中收集到太多信息。 我可以看到一些处于timed_waiting状态的线程,但没有一个被阻塞或者没有看到任何死锁检测。 因此,我们已将搜索转向堆转储分析。

答:我正在使用MAT进行堆转储分析。 我读过一些博客。 根据这些,我试图形成我的结论。 我想validation一下我的理解。

基本类加载器资源管理器视图

问题:从上图中我们可以看到1和2中有多个相同类型的类加载器。 为什么会这样? 事实上,sun.reflect.DelegatingClassLoader有超过1000个条目。 我无法理解这是什么。

现在,让我们深入研究WebappClassLoader的第一个

B.

深入研究WebappClassloader的第一个实例

Q1。 这些是这个类加载器定义/加载的类的列表吗? 正如我们在3中看到的那样,有一个父元素。 这是否意味着这个类加载器总是首先咨询这个父类加载器,并检查它是否由它加载。 如果它的祖先的层次结构不可能加载该类,那么只有它自己加载它? Is this understanding of the hierarchy of class loading correct?

我仍然没有得到Defined类和实例列数的含义? 什么实例? 我的意思是,加载类并不是实例化其对象,不是加载器的工作吗? 那个实例数是多少?

在这种情况下,我们可以看到:WebappClassloader有4361个定义的类和65973个实例。 类似地,URLClassLoader(它的父级)有766个定义的类和37399个实例。 它到底意味着什么? 它是否表明任何Classloader泄漏? 现在,当我深入查看WebappClassloader的第二个实例时,我看到它们具有相同的父级(0x80a887a8),并且由它加载/定义的类列表也几乎相同。 为什么会这样?

C.现在,当我在WebappClassloader的第一个实例上执行“GC根路径”时,我们可以看到这一点。 GC的路径

我的理解:很multithreading(从我们的应用程序中产生)引用了加载器。 这是一个糟糕的线程实现问题吗? 我需要找到问题的根本原因,然后我只想进一步解决它。

来自堆转储的其余部分的一些其他观察

  1. ThreadGroupContext和WebappClassloader消耗了大部分堆。
  2. 当我深入研究ThreadGroupContext的支配树时,我看到了WeakIdentityMap。 那些是什么? 这个dominatior树实际上向我们展示了什么? 当我们深入了解统治者树中的条目时,我们得到了哪些信息?

具有传出引用的向下钻取视图:

具有传出引用的向下钻取视图

带有传入引用的向下钻取视图:我不明白这一点。 这是什么? 这是内存泄漏吗?

在此处输入图像描述

  1. 当我在ThreadGroupContext上执行"Path to GC root" ,它显示这是一个GC根。 那为什么不收垃圾,为什么要保留浪费大量的内存?

请求建议!

  1. 如何避免泄漏和类加载器泄漏?
  2. 如何设计线程实现,其中:对于每个请求,都有一个网络调用到其他服务器,并且只能在外部服务器上建立一个连接所以在某种程度上,如果有多个传入请求到我们的服务器,每个请求都可以只能顺利使用外部服务器进行处理。 因此,我们在线程转储中看到了很多WAITING线程。 对这样的要求有任何想法。 我听说过TASK设计模式https://www.developerdotstar.com/mag/articles/troche_taskpattern.html ,这适用于我们的情况吗?

  3. 如何有效地利用MAT来计算泄漏?