我怎样才能弄清楚是什么在固定着未被挤压的物体上?

2022-09-03 09:01:04

我们的一个程序有时会在一个用户的计算机上出现错误,但当然不是在我测试它时。我刚刚使用JProfiler运行它(在10天的评估许可证上,因为我以前从未使用过它),并根据我们的代码前缀进行过滤,总大小和实例数量的最大块是特定简单类的8000多个实例。OutOfMemory

我点击了JProfiler上的“垃圾收集”按钮,我们其他类的大多数实例都消失了,但这些特定的实例却没有。我再次运行测试,仍然在同一实例中,它创建了4000多个类的实例,但是当我单击“垃圾回收”时,这些实例消失了,留下了8000多个原始实例。

这些实例确实会在各个阶段卡入各种集合中。我假设它们没有被垃圾回收的事实一定意味着某些东西保留了对其中一个集合的引用,因此保留了对对象的引用。

任何建议,我如何弄清楚什么是坚持参考?我正在寻找在代码中寻找什么的建议,以及如果有的话,在JProfiler中找出答案的方法。


答案 1

转储堆并检查它。

我相信有多种方法可以做到这一点,但这里有一个简单的方法。此描述适用于 MS Windows,但可以在其他操作系统上执行类似的步骤。

  1. 如果还没有 JDK,请安装它。它带有一堆整洁的工具。
  2. 启动应用程序。
  3. 打开任务管理器并找到java.exe(或您正在使用的任何可执行文件)的进程ID(PID)。如果默认情况下未显示 PID,请使用“查看>选择列...”以添加它们。
  4. 使用 jmap 转储堆。
  5. 在您生成的文件上启动 jhat 服务器,然后打开浏览器以 http://localhost:7000(默认端口为 7000)。现在,您可以浏览您感兴趣的类型以及实例数量,对它们的引用等信息。

下面是一个示例:

C:\dump>jmap -dump:format=b,file=heap.bin 3552

C:\dump>jhat heap.bin
Reading from heap.bin...
Dump file created Tue Sep 30 19:46:23 BST 2008
Snapshot read, resolving...
Resolving 35484 objects...
Chasing references, expect 7 dots.......
Eliminating duplicate references.......
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

为了解释这一点,理解Java使用的一些数组类型命名法是很有用的 - 比如知道类[Ljava.lang.Object;实际上意味着Object[]类型的对象。


答案 2

试试 Eclipse Memory Analyzer。它将为每个对象显示它如何连接到GC根 - 一个没有被垃圾回收的对象,因为它是由JVM持有的。

有关 Eclipse MAT 如何工作的更多信息,请参阅 http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/27/automated-heap-dump-analysis-finding-memory-leaks-with-one-click/