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 吗?
有什么想法为什么它不能正确地捡垃圾吗?
So I have this extremely memory-intensive Java application I'm building, which builds a tree of millions of nodes. Using the handy dandy Runtime methods for getting heap information, I built a nice little method that displays the current memory usage, as shown below:
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) + "%");
}
So just to test it out, I had the tree expand its root node (into 2128 children), and then expanded each one of those children (for a total of approx. 4 million nodes in the tree). The memory displays 11% used. I then set the root of the tree to be one of the root's children, and in doing so remove all references to the root's other children. Theoretically, this should remove 2127/2128 of the original root's children. I ran Java's Runtime.getRuntime().gc() method for forced garbage collection, and told it to display the memory usage again. This time, I got 10%. In theory, should this new percentage not be more like 0.05%, or 1/2128th of the value before setting the new root?
Any thoughts why it's not picking up the garbage properly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
System.gc
(以及等效的Runtime.gc
)方法是向垃圾收集器建议应该收集垃圾的建议,因此它并不是真正的一种方法“强制垃圾回收”:来自
System.gc
方法的 Java API 规范:(强调。)
此外,在一点技术细节上,即使确实发生了垃圾收集,请记住,除了您的程序之外,Java 虚拟机上还存在其他对象,因此将会有还有一些内存开销。
实际粗略了解树占用了多少内存的一种方法是检查创建树之前和之后的内存使用情况 - 但请注意,即使这样,在树被占用时也可能会发生一些垃圾收集。正在建设中,所以即使这也不是一个完美的衡量标准。
这里最好的选择可能是使用分析器(例如
jvisualvm
(随 JDK 一起提供),实际看看有多少堆被什么东西使用了。The
System.gc
(and the equivalentRuntime.gc
) method is a suggestion to the garbage collector that garbage should be collected, so it not truly a way to "force garbage collection":From the Java API Specification for the
System.gc
method:(Emphasis added.)
Furthermore, on a little bit of a technicality, even if the garbage collection did take place, keep in mind that there are other objects that are present on the Java virtual machine aside from your program, so there's going to be some memory overhead from that as well.
One way to actually get a rough idea of how much memory is being occupied by your tree is to check the memory usage before and after creating your tree -- but note that even then, there may be some garbage collection taking place while your tree is being built, so even that isn't going to be a perfect metric.
Probably the best option here is to employ a profiler (such as the
jvisualvm
which comes with the JDK) to actually take a look at how much of the heap is being used by what.您应该尝试分析您的应用程序!
You should try to profile your application instead!