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

标签 java methodology enterprise legacy-code memory-leaks

我必须在Java应用程序中找到内存泄漏。我对此有一些经验,但希望对此提供一些方法学/策略方面的建议。欢迎任何引用和建议。

关于我们的情况:

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

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

    最佳答案

    如果不了解底层代码,这几乎是不可能的。如果您了解底层代码,则可以更好地根据堆转储中获得的数十亿比特信息的谷类资源对小麦进行分类。

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

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

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

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

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

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

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

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

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

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

    然后,我将考虑其中的一些差异,从运行中剔除掉所有失败的类,并对结果进行并集。最后,我将提供在特定时间范围内不断增长的类(class)列表。显然,这些是泄漏类的主要候选人。

    但是,有些类保留了一些,而另一些则用了GC。这些类可能很容易在总体上上升和下降,但仍然会泄漏。因此,它们可能不属于“总是上升”的类别。

    为了找到这些,我将数据转换为时间序列并将其加载到数据库中,特别是Postgres。 Postgres很方便,因为它提供了statistical aggregate functions,因此您可以在数据上进行简单的linear regression analysis,并找到趋向上升的类,即使它们并不总是位于图表的顶部。我使用了regr_slope函数,以寻找具有正斜率的类。

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

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

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

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

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

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

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

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

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

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

    关于java - 在大型Java堆转储中查找内存泄漏的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2511315/

    相关文章:

    Java从类方法中获取多个值

    java - 无法修复数组索引越界错误

    asp.net-mvc - 作为一个团队开发 ASP.NET MVC 应用程序?

    ios - Unable to Download 'AppName' 此时无法下载

    c++ - 在 Visual Studio Enterprise 2017 中禁用自动生成的评论

    java - 如何以网络模式启动GWT?

    java - 如何修复Java中的 'Bound mismatch'

    language-agnostic - TDD 对于小型项目来说是不是太过分了?

    process - 作为开发过程方法论的快速回顾和介绍,应该阅读什么?

    ios - 通过 SOTI Mobicontrol 分发 iOS 应用程序需要什么