我们的一个程序有时也得到一个OutOfMemory
一个用户的计算机上的错误,但当然不是当我测试它。 我只是JProfiler的运行它(在10天的评估许可证,因为我以前从未使用过它),我们的代码前缀,无论是在总规模和实例的数量最大的一块过滤是一个特定的简单类的实例8000+ 。
我点击了“垃圾收集”按钮上的JProfiler,和其它类我们的大多数情况下就走了,而不是这些特定的人。 我再次运行测试,还是在同一个实例,它创造4000+以上的类的实例,但是当我点击“垃圾收集”,那些走了留下8000+原有的。
这些实例都陷到在不同阶段不同的类别。 我假设的事实,他们没有收集一定意味着事情是持有到一个参考,这样的控股到的对象的引用集合的一个垃圾。
任何建议,我怎么能弄清楚什么是抱着到参考? 我在寻找的代码寻找什么建议,以及如何找出这在JProfiler的,如果有。
Answer 1:
转储堆,并检查它。
我敢肯定有这样做的方法不止一种,但这里是一个简单的问题。 这个说明对于MS Windows,但可以采取其他操作系统类似的步骤。
- 安装JDK,如果你不已经拥有了它。 它配备了一堆灵巧的工具。
- 启动应用程序。
- 打开任务管理器,并找到java.exe的(或任何可执行您正在使用)的进程ID(PID)。 如果PID的默认情况下不显示,使用视图>选择列...添加它们。
- 使用JMAP转储堆。
- 启动你生成的文件服务器与jHat,打开你的浏览器的http://本地主机: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 []的对象。
Answer 2:
尝试Eclipse的内存分析器。 它会告诉你如何将它连接到一个GC根的每个对象 - 一个对象,它是不是垃圾收集,因为它是由JVM举行。
见http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/27/automated-heap-dump-analysis-finding-memory-leaks-with-one-click/用于Eclipse的MAT如何工作的更多信息。
Answer 3:
我想看看你的类集合(尤其是静态的)(包含HashMap是一个很好的起点)。 举个例子的代码:
Map<String, Object> map = new HashMap<String, Object>(); // 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的或者一些其他集合有也不会被垃圾收集对象的引用。
Answer 4:
没有银弹那里,你必须使用Profiler来确定持有这些不需要的对象集合,并找到他们应该已被删除代码的地方。 作为JesperE说,静态集合是看首位。
Answer 5:
一个显而易见的候选者是finalisers对象。 他们可以停留,而他们的finalize方法被调用。 他们需要收集,然后将最终(通常只是一个单一的finaliser线程),然后再收集。
另外要注意,你可以得到一个OOME因为GC未能收集足够的内存,尽管有实际是足够要创建的对象请求。 否则表现会磨到地面。
Answer 6:
留意静态容器。 在静态容器中的任何对象都将保留,只要类加载。
编辑:取消了对WeakReference的不正确的话。
Answer 7:
我刚才看了这个文章,但我很抱歉,我不记得在哪里。 我想这可能是在这本书“有效的Java”。 如果我发现参考,我会更新我的答案。
它概述了两种重要的教训是:
1)Final方法告诉GC时剔除的对象做什么,但它并不要求它这样做,也没有要求它做的方式。
2)现代相当于在非托管内存环境中的“内存泄漏”的,是被遗忘的引用。 如果不设置到对象为空的所有引用,当你用它做,对象将永远不会被淘汰。 实现您自己的集合类,或您自己的包装,管理集合时,这是最重要的。 如果你有一个游泳池或堆栈或队列,并且不设置斗空当“删除”,从收藏的对象时,一桶对象是在将保留该对象还活着,直到桶被设置为参照另一个对象。
免责声明:我知道提到这个其他答案,但我想提供更多的细节。
Answer 8:
我已经使用了Yourkit Java剖析( http://www.yourkit.com性能优化)上的Java 1.5。 它提供了如何在内存泄漏工作的部分。 我觉得它有用。
http://www.yourkit.com/docs/75/help/performance_problems/memory_leaks/index.jsp
你可以得到15天的eval: http://www.yourkit.com/download/yjp-7.5.7.exe
BR,
〜一
Answer 9:
收藏已经提到。 另一个难以找到的位置,如果你使用多个类加载器,如旧的类加载器可能无法收回,直到所有引用都消失了垃圾。
同时检查静态 - 这是讨厌。 日志框架可以让事情变得开放这样可以保持在自定义追加程序引用。
你有没有解决这个问题?
Answer 10:
几点建议:
- 作为高速缓存无限的地图,尤其是当静
- ThreadLocals在服务器的应用程序,因为线程通常不会死,所以ThreadLocal中不会释放
- 实习字符串(Strings.intern()),这导致在一堆字符串在PermSpace
Answer 11:
如果你在一个垃圾回收的语言越来越OOM错误,这通常意味着有一些记忆不被占的收集。 也许你的对象持有的非Java资源? 如果是的话,那么他们就应该有某种“关闭”的方法,以确保即使没有收集到的Java对象很快资源被释放。
文章来源: How can I figure out what is holding on to unfreed objects?