我怎样才能弄清楚是什么保留了未释放的对象?

2022-01-16 00:00:00 garbage-collection java jprofiler

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

One of our programs is sometimes getting an OutOfMemory error on one user's machine, but of course not when I'm testing it. I just ran it with JProfiler (on a 10 day evaluation license because I've never used it before), and filtering on our code prefix, the biggest chunk both in total size and number of instances is 8000+ instances of a particular simple class.

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

I clicked the "Garbage Collect" button on JProfiler, and most instances of other classes of ours went away, but not these particular ones. I ran the test again, still in the same instance, and it created 4000+ more instances of the class, but when I clicked "Garbage Collect", those went away leaving the 8000+ original ones.

这些实例确实会在不同阶段陷入不同的集合中.我假设它们没有被垃圾收集这一事实一定意味着某些东西正在持有对其中一个集合的引用,因此它正在持有对对象的引用.

These instances do get stuck into various Collections at various stages. I assume that the fact that they're not garbage collected must mean that something is holding onto a reference to one of the collections so that's holding onto a reference to the objects.

有什么建议可以让我弄清楚参考资料中的内容是什么?我正在寻找有关在代码中寻找什么的建议,以及在 JProfiler 中找到它的方法(如果有).

Any suggestions how I can figure out what is holding onto the reference? I'm looking for suggestions of what to look for in the code, as well as ways to find this out in JProfiler if there are.

推荐答案

转储堆并检查它.

我确信有不止一种方法可以做到这一点,但这里有一个简单的方法.此说明适用于 MS Windows,但也可在其他操作系统上执行类似步骤.

I'm sure there's more than one way to do this, but here is a simple one. This description is for MS Windows, but similar steps can be taken on other operating systems.

  1. 如果您还没有 JDK,请安装它.它带有一堆简洁的工具.李>
  2. 启动应用程序.
  3. 打开任务管理器并找到 java.exe(或您正在使用的任何可执行文件)的进程 ID (PID).如果默认情况下未显示 PID,请使用 View > Select Columns... 添加它们.
  4. 使用 jmap 转储堆.
  5. 在您生成的文件上启动 jhat 服务器并打开浏览器到 http://localhost:7000(默认端口为 7000).现在您可以浏览您感兴趣的类型以及实例数量、引用它们的内容等信息.
  1. Install the JDK if you don't already have it. It comes with a bunch of neat tools.
  2. Start the application.
  3. Open task manager and find the process id (PID) for java.exe (or whatever executable you are using). If the PID's aren't shown by default, use View > Select Columns... to add them.
  4. Dump the heap using jmap.
  5. Start the jhat server on the file you generated and open your browser to http://localhost:7000 (the default port is 7000). Now you can browse the type you're interested in and information like the number of instances, what has references to them, etcetera.

这是一个例子:

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 使用 - 就像知道 class [Ljava.lang.Object; 真的意味着 Object[] 类型的对象.

To interpret this, it is useful to understand some of the array type nomenclature Java uses - like knowing that class [Ljava.lang.Object; really means an object of type Object[].

相关文章