当前位置: 首页 > 面试题库 >

在大型Java堆转储中查找内存泄漏的方法

阚英武
2023-03-14
问题内容

我必须在Java应用程序中找到内存泄漏。我对此有一些经验,但希望就此方法论/战略提出建议。欢迎任何参考和建议。

关于我们的情况:

  1. 堆转储大于1 GB
  2. 我们有5次堆放场。
  3. 我们没有任何测试案例可以激发这一点。仅在使用至少一个星期后,它才会在(大规模)系统测试环境中发生。
  4. 该系统建立在内部开发的传统框架上,该框架具有许多设计缺陷,以至于无法将它们全部计算在内。
  5. 没有人深入了解该框架。它已被转移到 一个 在印度的家伙谁勉强回复电子邮件保存起来。
  6. 我们已经完成了快照堆转储,并得出结论,没有一个组件随时间增加。一切都是缓慢增长的。
  7. 上面的内容为我们指明了一个方向,那就是框架自有的ORM系统无限制地增加了其使用率。(此系统将对象映射到文件吗?!实际上不是ORM)

问题: 什么方法可以帮助您成功解决企业级应用程序中的漏洞?


问题答案:

如果不了解底层代码,这几乎是不可能的。如果您了解基础代码,那么您可以更好地根据堆转储中获得的成千上万的信息来区分小麦。

同样,您不知道某个类为何存在,就无法知道是否存在泄漏。

我刚刚花了过去的两周时间来完成这项工作,并且我使用了一个迭代过程。

首先,我发现堆分析器基本上没有用。他们无法有效地分析巨大的堆。

相反,我几乎完全依靠jmap直方图。

我想您对这些很熟悉,但对于那些不是:

jmap -histo:live <pid> > dump.out

创建活动堆的直方图。简而言之,它告诉您类名以及堆中每个类有多少个实例。

我每天每隔5分钟,每天24小时定期倾倒垃圾。对于您来说,这可能太细微了,但要旨是相同的。

我对此数据进行了几种不同的分析。

我编写了一个脚本,以获取两个直方图,并转储它们之间的差异。因此,如果第一个转储中的java.lang.String为10,第二次为15,我的脚本将吐出“ 5
java.lang.String”,告诉我它上升了5。如果下降,则数字将为负。

然后,我将考虑其中的几个差异,剔除所有从运行到运行的所有类,并合并结果。最后,我将提供在特定时间范围内不断增长的课程列表。显然,这些是泄漏类的主要候选者。

但是,某些类保留了一些,而其他类则保留了GC。这些类在总体上可以轻易地上下波动,但仍然会泄漏。因此,它们可能不属于“总是上升”的类别。

为了找到这些,我将数据转换为时间序列并将其加载到数据库中,特别是Postgres。Postgres很方便,因为它提供了统计聚合函数,因此您可以对数据进行简单的线性回归分析,并找到呈上升趋势的类,即使它们并不总是位于图表的顶部。我使用了regr_slope函数,以寻找具有正斜率的类。

我发现此过程非常成功,而且非常有效。直方图文件不是很大,并且很容易从主机上下载它们。它们在生产系统上运行并不是很昂贵(它们确实会强制使用大型GC,并且可能会阻塞VM一点)。我在具有2G
Java堆的系统上运行它。

现在,所有可以做的就是确定潜在的泄漏类。

在这里,您可以了解如何使用这些类,以及是否应该使用它们。

例如,您可能会发现您有很多Map.Entry类或其他一些系统类。

除非您只是简单地缓存String,否则事实是这些系统类,而“违规者”可能不是“问题”。如果要缓存某些应用程序类,则该类可以更好地指示问题所在。如果您不缓存com.app.yourbean,则不会绑定任何关联的Map.Entry。

一旦有了一些类,就可以开始爬网代码库以查找实例和引用。由于您拥有自己的ORM层(不管是好是坏),因此至少可以轻松查看其源代码。如果您的ORM正在缓存内容,则可能是在缓存包装您的应用程序类的ORM类。

最后,您可以做的另一件事是,一旦知道了类,就可以启动服务器的本地实例,该实例具有更小的堆和更小的数据集,并使用一个探查器对此进行监视。

在这种情况下,您可以进行仅影响您认为可能泄漏的事物中的1个(或少数)的单元测试。例如,您可以启动服务器,运行直方图,执行单个操作,然后再次运行直方图。泄漏的类应增加1(或任何工作单位)。

探查器可能可以帮助您跟踪“现在泄露”的类的所有者。

但是,最后,您将必须对代码库有所了解,以便更好地了解什么是泄漏,什么不是泄漏以及为什么对象在堆中根本存在,而更少地说明为什么可以保留它作为堆中的泄漏。



 类似资料:
  • 我们有一个使用eclipse-jetty版本8.1.6的java webserver。最近我们开始注意到内存不足的错误。我们对活动线程数的分析很少。这似乎在100左右是合理的。该进程具有5GB最大堆内存和4GB初始堆内存。 webserver平均每分钟接收350个请求。此外,我们在ELB(kubernetes服务)后面运行许多这样的实例。跑了几个小时后,我们注意到了这个OOM。这个问题是随机的,它

  • 我已经用工具从运行了几天的Java应用程序中生成了一个堆转储文件,这将导致一个很大的二进制堆转储文件。 我如何在IntellIJ IDEA中对这个堆转储执行内存分析? 我知道有一些用于Eclipse和Netbeans的工具,但如果可能的话,我更愿意使用IDEA。 分析的基本结果将告诉我每个对象在内存中的实例数(每个类),以便我能够开始调试内存泄漏。

  • 我需要找到Flutter的内存泄漏。如何找到他们?以及如何为测试创建内存泄漏?

  • 问题描述:我们在一个web应用程序(在CQ5上)中面临以下问题: 系统配置详细信息:系统内存: 7GB Xmx: 3.5 GB Xms: 1 GB MaxPermGen: 300MB最大观察线程数: 620(包括300个超文本传输协议请求服务线程)Xss:默认值 问题是cq5 java进程(运行servlet引擎)消耗的内存随着时间的推移而不断增加。一旦达到6到6.5GB以上(系统内存达到7GB)

  • 遵循下面的过程,但我无法分析转储生成。 null 提前谢了。

  • 我的应用程序需要大约10GB的RAM用于特定输入,而对于常规输入,大约1GB就足够了。通过对JProfiler进行更仔细的分析,可以发现(在GC之后)java的标准类使用了相当多的内存。util* :