我们的项目有时得到一个 OutOfMemory 错误的一个用户的机器,但当然不是当我测试。我只是跑了它与JProfiler(上一个10天的评估许可证,因为我从未使用过),以及过滤在我们的前缀码,最大的一块都在总额大小和数量的实例是8000+实例,特别是简单的类。

我点击"垃圾收集"的按钮上JProfiler,大多数情况下的其他类别的我们回去,但不是这些特定的人。我跑了再次试验,仍在同一个实例,它创造了4000多类实例,但是当我点击"垃圾收集",这些走了离开8000+原有的。

这些情况下得到坚持到的各种收藏在各个阶段。我认为,事实上,他们没有垃圾收集必须的意思是,什么是保持一个参考的一个集合,以便保持一个参考的对象。

任何建议我怎么可以弄清楚什么是保持到的参考?我正在寻找建议,在寻找什么代码,以及如何找到这个了在JProfiler如果有。

有帮助吗?

解决方案

转储堆并检查它。

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

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

    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保存。

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

我会在你的课程中看到集合(尤其是静态集合)(HashMaps是一个很好的起点)。以此代码为例:

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或其他一些集合具有对该对象的引用,它就不会被垃圾回收。

那里没有银弹,您必须使用探查器来识别容纳那些不需要的对象的集合,并在代码中找到它们应该被移除的位置。正如JesperE所说,静态集合是第一个看待它的地方。

一个明显的候选人是具有终结者的对象。他们可以在调用finalize方法时逗留。需要收集它们,然后最终确定(通常仅使用一个终结器线程),然后再次收集。

还要注意你可以获得一个OOME,因为gc无法收集足够的内存,尽管实际上已经有足够的内容来创建对象请求了。否则,表演就会陷入困境。

留意静电容器。只要加载了类,静态容器中的任何对象都将保留。

编辑:删除了WeakReference上的错误备注。

我刚读了一篇关于此的文章,但很抱歉我不记得在哪里。我认为它可能出现在“Effective Java”一书中。如果我找到了参考文献,我会更新我的答案。

它概述的两个重要课程是:

1)最终方法告诉gc当它剔除对象时要做什么,但是它没有要求它这样做,也没有办法要求它这样做。

2)现代相当于“记忆泄漏”的现象。在非托管内存环境中,是被遗忘的引用。如果在完成对象时未将对象的所有引用设置为 null ,则该对象将永远被剔除。这在实现您自己的Collection或您自己的管理Collection的包装器时最为重要。如果您有一个池,一个堆栈或一个队列,并且在您“删除”时没有将存储桶设置为 null 来自集合的对象,该对象所在的存储桶将使该对象保持活动状态,直到该存储桶被设置为引用另一个对象。

免责声明:我知道其他提到的答案,但我想提供更多细节。

我使用了Yourkit Java分析器( http://www.yourkit.com )来提高性能对java 1.5的优化。它有一节介绍如何解决内存泄漏问题。我发现它很有用。

http://www.yourkit.com/docs /75/help/performance_problems/memory_leaks/index.jsp

您可以获得15天的评估: http://www.yourkit的.com /下载/ YJP-7.5.7.exe

BR,结果 〜A

已经提到了收藏品。另一个难以找到的位置是你使用多个ClassLoader,因为在所有引用都消失之前,旧的类加载器可能无法被垃圾收集。

同时检查静力学 - 这些都是令人讨厌的。日志框架可以保持打开状态,这可以保留自定义appender中的引用。

你解决了这个问题吗?

一些建议:

  • 无限制地图用作缓存,特别是当静态的
  • ThreadLocals在服务器的应用程序,因为线,通常不会死,所以在线程本地是没有释放
  • 实习串(Strings.实习生()),这导致在一堆字符串中PermSpace

如果您在垃圾收集语言中收到OOM错误,通常意味着收集器不会记录某些内存。也许你的对象持有非java资源?如果是这样,那么他们应该有某种“关闭”方法,以确保即使没有尽快收集Java对象也会释放资源。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top