是否可以反射性地检查 Java 中的内存泄漏? [关闭]

Posted

技术标签:

【中文标题】是否可以反射性地检查 Java 中的内存泄漏? [关闭]【英文标题】:Is it possible to reflectively check for memory leaks in java? [closed] 【发布时间】:2012-09-17 17:22:58 【问题描述】:

所以,我萌生了写一些代码,可以在测试中自动检测并指出潜在的内存泄漏的想法,我只是想在遇到麻烦之前看看我的想法是否合理。

本质上,内存泄漏被定义为越来越多的未使用引用。在 Java 中,与 C++ 相比,这种危险显着降低,因为我们没有悬空指针或忘记 delete() 等危险。

所以这限制了我们在 Java 中发生内存泄漏的方式。我们可以对 Object 进行静态引用,也可以在当前运行的线程中进行本地引用,仅此而已,对吧?

然后,我的想法是编写一个例程,查看所有已知的项目类文件,并提取所有静态引用。然后一个引用需要被“递归”下来,并且它所拥有的所有实例引用都需要被计数。一个对象引用需要一些内存,而基元需要一些内存,我们可以计算所有这些。您可以触发此例程一次,以获得基线,然后执行您认为会导致内存泄漏的事情,然后再次运行例程并比较结果。可以设置一个增量阈值,然后您可以手动确定哪些对象有目的地变大,哪些对象变大了,但不应该。

当然,这是一个测试工具,但是,在我从事的项目中,通常我只能在生产环境中重现这些错误,并且有很多用户,因此使用真正的分析器并不总是一种选择.内置此功能可以省去实际运行分析器的麻烦,并且大部分时间都可以正常运行,除非在生产产品上诊断问题。

我看到的唯一问题是,当前正在运行的线程中的局部变量无法以这种方式访问​​,但是,知道这一限制,可能需要代码将这些本地(但长期引用)注册到测试类中本身,它将在静态变量中保存对这些对象的弱引用,从而允许对引用进行计数。

垃圾收集将是一个问题,所以基本上,我会通过创建一个未引用的对象来“强制”垃圾收集,该对象会覆盖 finalize 以在收集它时通知我的线程,这将导致我的 GC 检测器停止阻塞,并且然后运行检漏仪。

所以,我的问题是,这听起来合理吗?你认为这会产生有用的结果吗?

【问题讨论】:

如果它是合理的,那么现在有人会这样做并且赚了很多钱。我认为你的想法不会产生我现在无法得到的有用结果。 那你是怎么得到这些结果的?我想到这个的原因是因为我怀疑内存泄漏,虽然我不知道从哪里开始。 我认为您应该使用 Visual VM 来查找内存泄漏。 您可以告诉生产 JVM 在内存不足时转储诊断信息。然后,您可以发布该诊断信息以识别问题。我相信大多数供应商都支持倾销 hprof 信息。 【参考方案1】:

所以这限制了我们在 Java 中发生内存泄漏的方式。我们可以对 Object 进行静态引用,也可以在当前运行的线程中进行本地引用,仅此而已,对吧?

没有。查看Creating a memory leak with Java 对于替代原因的非详尽列表,您的方法无法检测到其中的大部分。

在我从事的项目中,通常我只能在生产中重现这些错误,而且有很多用户,因此使用真正的分析器并不总是一种选择。内置此功能可以省去实际运行分析器的麻烦,并且大部分时间都可以正常运行,除非在生产产品上诊断问题。

您始终可以让生产系统写入堆转储(Oracle JVM 甚至有一个setting 来在发生 OutOfMemoryError 时写入堆转储。)。然后,您可以分析这些堆转储(有多种工具可用于此目的,其中一些工具通过应用一些启发式方法自动找到“泄漏嫌疑人”)。

【讨论】:

【参考方案2】:

从 Java 1.5 开始,您有了 jmap 可以打印类直方图。

【讨论】:

以上是关于是否可以反射性地检查 Java 中的内存泄漏? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

任何可以找到内存泄漏java代码的java静态代码分析器?

Java中的内存泄漏

valgrind - 检查程序中的内存泄漏问题

Java内存泄漏

valgrind--CPP程序内存泄露检查工具

java内存溢出怎么解决?