【问题标题】:Java garbage collection problemJava垃圾回收问题
【发布时间】:2011-06-25 08:42:14
【问题描述】:

因此,我正在构建这个非常占用内存的 Java 应用程序,它构建了一个包含数百万个节点的树。使用方便的花花公子 Runtime 方法获取堆信息,我构建了一个不错的小方法来显示当前内存使用情况,如下所示:

public void displayMemoryUsage() {
    long maxMem = Runtime.getRuntime().maxMemory();
    long freeMem = Runtime.getRuntime().freeMemory();
    long heapMem = Runtime.getRuntime().totalMemory();
    long usedMem = heapMem - freeMem;
    System.out.println("Memory used: " + (int) (usedMem * 100 / maxMem) + "%");
}

所以只是为了测试它,我让树扩展它的根节点(到 2128 个子节点),然后扩展每个子节点(树中总共大约 400 万个节点)。内存显示 11% 已使用。然后我将树的根设置为根的孩子之一,并在这样做时删除对根的其他孩子的所有引用。从理论上讲,这应该删除原始根的 2127/2128 个孩子。我运行 Java 的 Runtime.getRuntime().gc() 方法进行强制垃圾回收,并告诉它再次显示内存使用情况。这一次,我得到了 10%。理论上,这个新百分比不应该更像是 0.05%,还是设置新根之前的值的 1/2128?

任何想法为什么它不能正确地捡垃圾?

【问题讨论】:

标签: java memory-management heap-memory


【解决方案1】:

System.gc(和等效的Runtime.gc)方法是建议垃圾收集器应该收集垃圾,所以它不是真正“强制垃圾收集”的方法:

来自System.gc 方法的 Java API 规范:

运行垃圾收集器。

调用 gc 方法表明 Java 虚拟机花费精力 朝着回收未使用的对象 为了让他们的记忆 目前占用可用于快​​速 重用。* 当控制权从 方法调用,Java 虚拟机 已尽最大努力收回 所有丢弃的对象的空间。

(已添加重点。)

此外,从技术上讲,即使确实发生了垃圾回收,请记住,除了您的程序之外,Java 虚拟机上还存在其他对象,因此会有一些内存开销也是如此。

实际粗略了解树占用了多少内存的一种方法是在创建树之前和之后检查内存使用情况——但请注意,即便如此,在创建树的过程中也可能会进行一些垃圾收集。你的树正在建造中,所以即使这也不是一个完美的指标。

这里最好的选择可能是使用分析器(例如 JDK 附带的 jvisualvm)来实际查看有多少堆正在被什么使用。

【讨论】:

    【解决方案2】:

    您应该尝试分析您的应用程序!

    【讨论】:

      【解决方案3】:
      1. 您确定任何地方都没有对已删除节点的引用吗?
      2. 您确定在 gc() 之后等待了足够长的时间,即您是否多次建议?

      【讨论】:

        猜你喜欢
        • 2011-03-31
        • 1970-01-01
        • 2014-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多