所以我有一个我正在构建的内存密集型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%使用。然后我将树的根设置为root的子节点之一,并在此过程中删除对root的其他子节点的所有引用。从理论上讲,这应该删除原始root的孩子的2127/2128。我为强制垃圾收集运行了Java的Runtime.getRuntime()。gc()方法,并告诉它再次显示内存使用情况。这一次,我得到了10%。理论上,在设置新根之前,这个新百分比是否应该更像是0.05%,或者是值的1/22128?
有什么想法为什么它没有正确地捡垃圾?
答案 0 :(得分:4)
System.gc
(和等效的Runtime.gc
)方法是垃圾收集器的建议应该收集垃圾,所以它不是真正的“强制垃圾”的方法集合“:
来自System.gc
方法的Java API规范:
运行垃圾收集器。
调用gc方法表明了这一点 Java虚拟机花费精力 回收未使用的物品 为了使他们记忆 目前可以快速占用 重用。 *当控制从中返回时 方法调用,Java虚拟机 我已尽最大努力收回 所有丢弃物体的空间。
(强调补充。)
此外,在一点技术性方面,即使垃圾收集确实发生了,请记住,除了程序之外,Java虚拟机上还有其他对象,因此会有一些内存也是开销。
实际大致了解树占用多少内存的一种方法是检查创建树之前和之后的内存使用情况 - 但请注意,即使这样,也可能会发生一些垃圾收集。你的树正在建造中,所以即便这样也不是一个完美的指标。
这里最好的选择可能就是使用一个分析器(比如JDK附带的jvisualvm
)来实际查看一下堆的使用量是多少。
答案 1 :(得分:1)
您应该尝试分析您的应用程序!
答案 2 :(得分:0)