Java垃圾回收会开始工作以防止内存交换吗?

12
举例来说,假设我将JVM的最大堆大小设置为4GB。然而,一旦我的应用程序达到约3GB,操作系统开始将一些内存交换到磁盘上。此时已经有几个对象超出范围,JVM可以首先垃圾回收旧对象,而不是请求更多内存。从性能角度来看,运行垃圾回收要比进行内存交换好。JVM的垃圾回收是否聪明地处理这种情况?我们是否可以以某种方式调整JVM以解决这种情况?
我知道垃圾回收有可能在达到3GB之前就运行,因此我们实际上永远不需要交换内存,但这并没有真正回答我的问题。
编辑:假设我的计算机有超过4GB的内存,但有时其他应用程序占用了部分内存,导致我剩余的内存少于4GB。我不想减少最大堆大小,因为大多数时候我都会有4GB,但我想知道GC在其他情况下是否足够聪明。
3个回答

9
JVM并不知道底层操作系统的内存管理。我记得不久前参加了一场有关GC优化的JavaOne会议,演讲者强调应始终确保有足够的空闲内存(RAM而非交换空间)供JVM运行,以避免尽可能地进行分页,因此永远不要为JVM分配比系统当前可用内存更多的内存。更重要的是,由于某些GC收集算法的工作方式,如果它们正在收集的内存块被分页,可能会产生巨大的性能损失。
因此,永远不要给JVM分配比您在系统中实际可用的内存更多的内存,或者如果您预计由于某些外部进程而导致内存消耗增加,则分配一个堆空间,以确保它永远不会被分页。如果无法满足这些条件,那么您需要更多的RAM :)
更新:在SO中搜索后,我发现了这篇文章。在其中,kdgregory认为分页不应该是一个问题,因为GC的工作方式,但他考虑的是由于正常情况下的分页,即内存长时间未被访问,而这不是您的情况,因为您将耗尽内存,而且肯定会开始分页。此外,如果您正在运行某个Linux版本,请查看John Ferminella的回答以及他的绝佳博客文章,解释如何理解和调整Linux中的交换空间。

2

垃圾回收器并不知道这种情况。不应指定一个比机器上可用内存更大的堆。解决方案是减小堆大小,并确保没有其他程序占用全部内存。

实际上,即使在 C 语言中也没有简单的方法来检查进程是否正在交换(如果有,请添加评论)。


1
在C中,您需要自己管理内存分配,因此您不应该在内存中保留不再需要的数据。假设您很好地回收了不再使用的内存,如果操作系统正在进行交换,这意味着没有更多未使用的内存。但对于Java而言并非一定如此。 - Mario Duarte

2
“Java虚拟机规范第三章”中提到,运行时数据区的内存布局、垃圾回收算法以及Java虚拟机指令的任何内部优化(例如将它们转换为机器码)都由实现者自行决定。
事实上,并不存在所谓的“Java垃圾回收”。Java虚拟机规范规定每个JVM实现都需要提供垃圾回收功能,但如何实现则由实现者自行决定。技术上来说,这至少是一个挑战。因为我们不希望仅仅因为某些页面已经被交换到虚拟内存中就触发垃圾回收,而是希望在内存管理即将将JVM页面交换到虚拟内存时触发垃圾回收。我怀疑这样的信息/通知是否存在于计算机系统中。
操作系统对Java虚拟机说:“嘿,在我将你的一些堆交换到虚拟内存之前最好现在清理一下。” Java虚拟机回应操作系统:“好的,请不要进行交换,我现在开始清理,等我完成会告诉你。”1457毫秒后,Java虚拟机对操作系统说:“感谢您的耐心等待,我已经尽可能地清理了,您现在可以继续进行交换了。”

谢谢您的回复。您说得完全正确,我应该更加清晰明了。我想到了Sun的JVM,但如果有其他实现方式也能实现这一点,那同样很有趣。 - Mario Duarte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接