我们的一个项目有时会得到一个 OutOfMemory
在一个用户的计算机上出错,但当然不是在我测试它时.我只是用JProfiler运行它(在10天的评估许可证上,因为我之前从未使用它),并且对我们的代码前缀进行过滤,总大小和实例数量中最大的块是特定简单类的8000多个实例.
我点击了JProfiler上的"Garbage Collect"按钮,我们其他类的大部分实例都消失了,但不是这些特殊的.我再次运行测试,仍然在同一个实例中,它创建了4000多个类的实例,但是当我点击"垃圾收集"时,那些离开了8000多个原始实例.
这些实例在各个阶段都会遇到各种集合.我认为它们不是垃圾收集的事实必然意味着某些东西持有对其中一个集合的引用,以便保持对对象的引用.
有什么建议我如何弄清楚什么是持有参考?我正在寻找在代码中寻找什么的建议,以及如果有的话在JProfiler中找到它的方法.
转储堆并检查它.
我确信这不止一种方法,但这是一个简单的方法.此描述适用于MS Windows,但可以在其他操作系统上执行类似的步骤.
如果您还没有安装JDK,请安装它.它配备了一堆巧妙的工具.
启动应用程序.
打开任务管理器,找到java.exe(或您正在使用的任何可执行文件)的进程ID(PID).如果默认情况下未显示PID,请使用"视图">"选择列..."添加它们.
使用jmap转储堆.
在您生成的文件上启动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 []类型的对象.
试试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/.
我会在你的课程中看看Collections(特别是静态的)(HashMaps是一个很好的起点).以此代码为例:
Mapmap = new HashMap (); // 1 Object String name = "test"; // 2 Objects Object o = new Object(); // 3 Objects map.put(name, o); // 3 Objects, 2 of which have 2 references to them o = null; // The objects are still being name = null; // referenced by the HashMap and won't be GC'd System.gc(); // Nothing is deleted. Object test = map.get("test"); // Returns o test = null; map.remove("test"); // Now we're down to just the HashMap in memory // o, name and test can all be GC'd
只要HashMap或其他一些集合具有对该对象的引用,它就不会被垃圾回收.