我知道垃圾收集在Java中是自动化的.但我明白,如果你System.gc()
在代码中编写,Java VM可能会或可能不会在运行时决定在那时进行垃圾收集.这是如何工作的?基于什么基础/参数,VM在看到GC时决定做(或不做)GC System.gc()
?是否有可能的例子在这种情况下将它放在代码中是个好主意?
在实践中,它通常决定进行垃圾收集.答案取决于很多因素,例如您正在运行的JVM,它所处的模式以及它正在使用的垃圾收集算法.
我不会在你的代码中依赖它.如果JVM即将抛出OutOfMemoryError,则调用System.gc()将不会停止它,因为垃圾收集器将在它进入极端之前尝试尽可能多地释放它.我在实践中看到它的唯一一次是在IDE中,它附加到用户可以点击的按钮,但即便如此,它也不是非常有用.
我能想到调用System.gc()的唯一例子是在分析应用程序以搜索可能的内存泄漏时.我相信分析器在获取内存快照之前调用此方法.
你无法控制java中的GC - VM决定.我从来没有穿过其中的情况下运行System.gc()
的需要.由于System.gc()
调用只是假设VM执行垃圾收集并且它还执行完全垃圾收集(多代堆中的新旧代),因此它实际上可能导致消耗超过必要的更多 cpu周期.
在某些情况下,向VM建议它现在进行完整收集可能是有意义的,因为您可能知道应用程序在繁重提升之前将在接下来的几分钟内处于空闲状态.例如,在应用程序启动期间初始化很多临时对象之后(即,我刚刚缓存了一大堆信息,我知道我将在一分钟左右没有获得太多活动).想象一下像eclipse这样的IDE启动 - 初始化它会做很多事情,所以也许在初始化之后立即执行一个完整的gc是有意义的.
Java语言规范不保证JVM在您调用时将启动GC System.gc()
.这就是为什么"可能会或可能不会决定在那时做GC".
现在,如果您查看OpenJDK源代码(它是Oracle JVM的主干),您将看到调用System.gc()
确实启动了GC循环.如果您使用其他JVM,例如J9,则必须检查其文档以找出答案.例如,Azul的JVM有一个连续运行的垃圾收集器,所以调用System.gc()
不会做任何事情
其他一些答案提到在JConsole或VisualVM中启动GC.基本上,这些工具可以远程调用System.gc()
.
通常,您不希望从代码中启动垃圾回收周期,因为它会混淆应用程序的语义.你的应用程序做了一些业务,JVM负责内存管理.您应该将这些问题分开(不要让您的应用程序进行一些内存管理,专注于业务).
但是,很少有情况下System.gc()
可以理解呼叫.例如,考虑微基准测试.没有人希望在微基准测试的中间发生GC循环.因此,您可以在每次测量之间触发GC循环,以确保每个测量都以空堆开始.
如果你打电话,你需要非常小心System.gc()
.调用它可能会给应用程序添加不必要的性能问题,并且无法保证实际执行集合.实际上可以System.gc()
通过java参数禁用显式-XX:+DisableExplicitGC
.
我强烈建议您阅读Java HotSpot垃圾收集中提供的文档,以获取有关垃圾收集的更多详细信息.
System.gc()
由VM实现,它的功能是特定于实现.例如,实施者可以简单地返回并且什么都不做.
至于何时发布手动收集,只有当你放弃一个包含大量较小集合的大型集合时才会这样做 -
Map
例如 - 当你想要尝试接受性能指数时在那里,但在大多数情况下,你不应该担心它.GC比你更清楚 - 很遗憾 - 大多数时候.
如果使用直接内存缓冲区,即使直接内存不足,JVM也不会为您运行GC.
如果您调用ByteBuffer.allocateDirect()
并且得到OutOfMemoryError,则可以在手动触发GC后发现此调用正常.
大多数JVM将启动GC(取决于-XX:DiableExplicitGC和-XX:+ ExplicitGCInvokesConcurrent开关)。但是,规范的定义不太明确,以便以后可以更好地实现。
规范需要澄清:错误#6668279 :(规范)System.gc()应该表明我们不建议使用也不保证行为
RMI和NIO在内部使用gc方法,它们需要同步执行,这是当前正在讨论的问题:
错误#5025281:允许System.gc()触发并发(而不是世界末日)完整集合