System.gc() 什么时候会发挥作用?

131
我知道Java中的垃圾回收是自动的。但我了解到,如果在代码中调用System.gc(),JVM可能会决定在那个时刻进行或不进行垃圾回收。这是如何精确工作的?JVM基于什么准则/参数来决定是否执行GC,当它看到System.gc()时?
是否有任何例子表明将此放入代码中是一个好主意?

4
这个概念过于复杂,无法在此进行详细说明,但这篇文章应该可以帮到你:http://chaoticjava.com/posts/how-does-garbage-collection-work/ - GEOCHET
具体行为取决于JVM,即实现相关。 - Thorbjørn Ravn Andersen
16个回答

2

在测试各种垃圾回收设置时,有很多要说的,但正如上面提到的,通常没有必要这样做。

我目前正在处理一个内存受限的环境和相对较大的数据量的项目——有一些大块数据将我的环境推向极限,即使我能够将内存使用量降低到理论上应该可以正常工作的水平,仍然会出现堆空间错误——详细的GC选项向我展示了它正在尝试进行垃圾回收,但无济于事。在调试器中,我可以执行System.gc(),确保有足够的内存可用……不是很多,但足够。

因此,我的应用程序唯一调用System.gc()的时间是当它即将进入为处理数据分配大缓冲区的代码段,并且可用的空闲内存测试表明我不能保证它。特别是,我正在查看一个1GB的环境,其中至少300MB被静态数据占用,非静态数据的大部分与执行相关,除非源数据至少为100-200 MB。这都是自动数据转换过程的一部分,因此从长远来看,所有数据存在的时间都相对较短。

不幸的是,虽然有关调整垃圾收集器的各种选项的信息是可用的,但似乎它主要是一个实验性的过程,需要理解如何处理这些特定情况所需的较低级别的细节并不容易获得。

尽管我正在使用System.gc(),但仍然继续使用命令行参数进行调整,并成功地提高了应用程序的总体处理时间,尽管无法克服处理较大数据块时遇到的障碍。也就是说,System.gc()是一种工具……一种非常不可靠的工具,如果你不小心使用它,你会更希望它不起作用。


2

我们无法强制进行垃圾回收。System.gc只是建议虚拟机进行垃圾回收,但真正运行机制的时间,没有人知道,这是JSR规范所述。


2
通常情况下,虚拟机在抛出OutOfMemoryException之前会自动执行垃圾回收,因此添加显式调用不应该有帮助,除非它将性能损失转移到了时间的早期。
然而,我认为我遇到了一个可能相关的情况。尽管我还没有测试它是否有任何影响:
当您内存映射文件时,我认为如果没有足够大的内存块可用,map()调用会抛出IOException。在map()文件之前进行垃圾回收可能有助于防止这种情况发生。你认为呢?

0

我无法想到一个明确的例子,说明何时运行显式GC是好的。

一般来说,运行显式GC实际上可能会带来更多的伤害,因为显式GC将触发完整的垃圾回收,这需要花费更长的时间,因为它要遍历每个对象。如果这个显式GC被反复调用,它很容易导致应用程序变慢,因为大量时间都花在运行完整的GC上。

或者,如果使用堆分析器检查堆,并且怀疑库组件正在调用显式GC,则可以通过将gc=-XX:+DisableExplicitGC添加到JVM参数中来关闭它。


2
我们调用System.gc()来尝试关闭我们的MappedByteBuffer对象,否则这些对象将不会被关闭,因此其他进程或文件截断也无法使用它们,即使我们在对象上调用'close()'。不幸的是,它仍然不能始终关闭它们。 - Tim Cooper

0
根据Bruce Eckel的《Java编程思想》,显式调用System.gc()的一个使用情景是强制执行finalization,即调用finalize方法。

注意:有一种方法可以强制运行终结器。 (问题实际上不在于运行终结器,而在于识别对象可以被终结,因为它没有引用) - eckes

0

虽然 system.gc 能够工作,但它会暂停整个程序:所有响应都会停止,以便垃圾回收器可以扫描每个对象以检查是否需要删除。如果应用是一个 Web 项目,则所有请求都将被停止,直到 gc 完成,这将导致您的 Web 项目在某一时刻无法工作。


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