System.gc()什么时候做某事?

时间:2008-09-15 20:20:17

标签: java garbage-collection

我知道垃圾收集在Java中是自动化的。但我明白,如果你在代码中调用System.gc(),那么JVM可能会或者可能不会决定在那时执行垃圾收集。这是如何工作的? JVM在看到System.gc()时决定做什么(或不做)的确切基础/参数是什么?

是否有任何示例,在这种情况下,将它放在代码中是个好主意?

17 个答案:

答案 0 :(得分:56)

实际上,通常决定进行垃圾收集。答案取决于很多因素,例如您正在运行的JVM,它所处的模式以及它正在使用的垃圾收集算法。

我不会在你的代码中依赖它。如果JVM即将抛出OutOfMemoryError,则调用System.gc()将不会停止它,因为垃圾收集器将在它进入极端之前尝试尽可能多地释放它。我在实践中看到它的唯一一次是在IDE中,它附加到用户可以点击的按钮上,但即便如此,它也不是非常有用。

答案 1 :(得分:28)

我能想到调用System.gc()的唯一例子是在分析应用程序以搜索可能的内存泄漏时。我相信分析器在获取内存快照之前调用此方法。

答案 2 :(得分:24)

你无法控制java中的GC - VM决定。我从未遇到System.gc() 需要的情况。由于System.gc()调用只是建议VM执行垃圾收集并且它还执行完全垃圾收集(多代堆中的新旧代),然后它实际上可以导致 MORE cpu周期消耗超过必要。

在某些情况下,向VM建议它现在进行完整收集可能是有意义的,因为您可能知道应用程序将在繁重提升之前的几分钟内处于空闲状态。例如,在应用程序启动期间初始化大量临时对象之后(即,我刚刚缓存了一大堆信息,我知道我将在一分钟左右没有获得太多活动)。想象一下像eclipse这样的IDE启动 - 初始化它会做很多事情,所以也许在初始化之后立即进行完整的gc是有意义的。

答案 3 :(得分:22)

Java语言规范不保证在您调用System.gc()时JVM将启动GC。这就是“此时可能会或可能不会决定使用GC”的原因。

现在,如果你看一下{JAME的主干OpenJDK source code,你会看到对System.gc()的调用确实启动了GC循环。如果您使用其他JVM,例如J9,则必须检查其文档以找出答案。例如,Azul的JVM有一个连续运行的垃圾收集器,所以对System.gc()的调用不会做任何事情

其他一些答案提到在JConsole或VisualVM中启动GC。基本上,这些工具可以远程调用System.gc()

通常,您不希望从代码中启动垃圾回收周期,因为它会混淆应用程序的语义。你的应用程序做了一些业务,JVM负责内存管理。您应该将这些问题分开(不要让您的应用程序进行一些内存管理,专注于业务)。

但是,很少有人可以理解对System.gc()的调用。例如,考虑微基准测试。没有人希望在微基准测试的中间发生GC循环。因此,您可以在每次测量之间触发GC循环,以确保每个测量都以空堆开始。

答案 4 :(得分:17)

如果致电System.gc(),您需要非常小心。调用它可能会给应用程序添加不必要的性能问题,并且无法保证实际执行集合。实际上可以通过java参数System.gc()禁用显式-XX:+DisableExplicitGC

我强烈建议您阅读Java HotSpot Garbage Collection处提供的文档,了解有关垃圾收集的详细信息。

答案 5 :(得分:10)

System.gc()由VM实现,它的功能是特定于实现。例如,实施者可以简单地返回并且什么都不做。

至于何时发布手动收集,只有当您放弃包含大量较小收藏品的大型收藏时,您才会想要这样做? 例如Map<String,<LinkedList>> - 并且你想尝试然后在那里接受性能打击,但是在大多数情况下,你不应该担心它。 GC比你更清楚 - 很遗憾 - 大部分时间都是。

答案 6 :(得分:8)

如果使用直接内存缓冲区,即使直接内存不足,JVM也不会为您运行GC。

如果你打电话给ByteBuffer.allocateDirect()并且你得到一个OutOfMemoryError,你可以在手动触发GC后找到这个电话。

答案 7 :(得分:3)

大多数JVM都会启动GC(取决于-XX:DiableExplicitGC和-XX:+ ExplicitGCInvokesConcurrent开关)。但是规范的定义不太明确,以便以后能够更好地实现。

规范需要澄清:Bug #6668279: (spec) System.gc() should indicate that we don't recommend use and don't guarantee behaviour

在内部,gc方法由RMI和NIO使用,它们需要同步执行,其中:目前正在讨论中:

Bug #5025281: Allow System.gc() to trigger concurrent (not stop-the-world) full collections

答案 8 :(得分:2)

我们永远不能强制垃圾收集。 System.gc只是建议垃圾收集的vm,但是,实际上机制运行的时间,没有人知道,这是JSR规范所述。

答案 9 :(得分:2)

在花时间测试各种垃圾收集设置方面有很多话要说,但正如上面提到的那样,它通常没用。

我目前正在开发一个涉及内存限制环境和相对大量数据的项目 - 有一些大型数据可以将我的环境推向极限,即使我能够带来内存用法下来,以便理论上它应该工作得很好,我仍然会得到堆空间错误---详细的GC选项告诉我它正在尝试垃圾收集,但无济于事。在调试器中,我可以执行System.gc(),并且确实有足够的内存可用......不是很多额外的,但足够了。

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

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

所有这一切,即使我使用System.gc(),我仍然继续使用命令行参数进行调整,并设法将我的应用程序的整体处理时间提高了相当大的数量,尽管无法克服了处理更大数据块所带来的绊脚石。话虽这么说,System.gc()是一个工具....一个非常不可靠的工具,如果你不小心你如何使用它,你会希望它不会更频繁地工作。

答案 10 :(得分:2)

Garbage CollectionJava中很好,如果我们在桌面/笔记本电脑/服务器中执行java编码的软件。您可以在System.gc()中致电Runtime.getRuntime().gc()Java

请注意,这些电话都不能保证做任何事情。它们只是jvm运行垃圾收集器的建议。无论是否运行GC,它都在JVM上。所以,简短回答:我们不知道它何时运行。更长的答案:JVM如果有时间就会运行gc。

我相信,Android同样适用。但是,这可能会降低您的系统速度。

答案 11 :(得分:1)

当运行显式GC时,我无法想到一个具体的例子。

通常,运行显式GC实际上可能会造成更多弊大于利,因为显式gc将触发完整集合,这会在通过每个对象时花费更长的时间。如果这个显式gc最终被重复调用,很容易导致应用程序变慢,因为花费了大量时间来运行完整的GC。

或者,如果使用堆分析器遍历堆并且您怀疑库组件要调用显式GC,则可以将其关闭添加:gc = -XX:+ DisableExplicitGC to JVM parameters。

答案 12 :(得分:1)

通常情况下,VM会在抛出OutOfMemoryException之前自动进行垃圾收集,因此添加显式调用应该没有用,除非它可能会将性能命中移动到更早的时刻。

但是,我认为我遇到了一个可能相关的案例。我不确定,因为我还没有测试它是否有任何影响:

当你对一个文件进行内存映射时,我相信当一个足够大的内存块不可用时,map()调用会抛出一个IOException。我认为,map()文件之前的垃圾收集可能有助于防止这种情况发生。你觉得怎么样?

答案 13 :(得分:1)

如果您想知道是否调用了System.gc(),那么当JVM执行垃圾收集时,您可以使用新的Java 7 update 4获取通知。

我不是100%确定{7}}类是在Java 7更新4中引入的,因为我在发行说明中找不到它,但我在GarbageCollectorMXBean中找到了这些信息.com网站

答案 14 :(得分:1)

简而言之:

参数取决于VM。

示例用法 - 不能想到一个用于运行时/生产应用程序,但是为某些分析工具运行它是很有用的,比如调用

// test run #1
test();
for (int i=0; i<10; i++) { 
// calling repeatedly to increase chances of a clean-up
  System.gc(); 
}
// test run #2
test();

答案 15 :(得分:0)

Bruce Eckel用Java思考,一个用于显式 System.gc()调用的用例是当你想强制终结时,即调用 finalize 方法

答案 16 :(得分:0)

当system.gc工作时,它将停止世界:所有响应都被停止,因此垃圾收集器可以扫描每个对象以检查是否需要删除它。如果应用程序是一个Web项目,所有请求都会在gc完成之前停止,这将导致您的Web项目无法在monent中工作。