2011-02-11 301 views
1

所以我有这个内存密集型的Java应用程序,它构建了一个有数百万个节点的树。利用方便的花花公子运行一些方法来获取堆信息,我建,显示当前内存的使用情况,如下图所示一个可爱的小方法:Java垃圾收集问题

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?

任何想法为什么它不正确拾取垃圾?

+6

对不起nitpicker ..但你不能_force_垃圾回收,你只是_suggest_ JVM这样做。 http://download.oracle.com/javase/6/docs/api/java/lang/Runtime.html#gc%28%29 – Nishant 2011-02-11 06:02:44

回答

4

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

从Java System.gc方法的API规范:

运行垃圾回收器。

调用gc方法表明, 的Java虚拟机的努力 朝 为了使内存回收未使用的对象,他们 当前占用快速 重用。 *当控制从 方法调用返回时,Java虚拟机 已尽最大努力从所有被丢弃的对象中收回 空间。

(着重号。)

此外,在一个技术性的一点点,即使垃圾收集确实发生,请记住,有一些存在于Java虚拟机上的其他对象除了你的程序,所以也会有一些内存开销。

实际获得有关树的内存占用量的一种方法是在创建树之前和之后检查内存使用情况 - 但请注意,即使此时可能会发生一些垃圾回收而你的树正在建造,所以即使这不会是一个完美的指标。

这里最好的选择可能是使用一个探查器(例如JDK附带的jvisualvm)来实际检查堆的使用量。

0
  1. 您确定没有对已删除节点的任何引用?
  2. 你确定你在gc()之后等了很长时间,也就是说你多次建议它吗?
1

您应该尝试改为调整您的应用程序!