129

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

是否有任何示例在这种情况下将其放入您的代码中是个好主意?

4

16 回答 16

61

在实践中,它通常决定进行垃圾回收。答案因许多因素而异,例如您正在运行的 JVM、它所处的模式以及它使用的垃圾收集算法。

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

于 2008-09-15T20:23:41.663 回答
30

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

于 2008-09-15T20:36:59.993 回答
29

您无法控制 Java 中的 GC——VM 决定。我从来没有遇到过需要System.gc()的情况。由于调用只是简单地暗示 VM 进行垃圾收集并且它还进行了完整的垃圾收集(多代堆中的旧代和新代),因此它实际上可能导致消耗更多的 cpu 周期而不是必要的。System.gc()

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

于 2008-09-15T20:27:20.720 回答
26

Java 语言规范不保证 JVM 会在您调用System.gc(). 这就是“可能会或可能不会决定在那个时候进行 GC”的原因。

现在,如果您查看作为 Oracle JVM 主干的OpenJDK 源代码,您会看到对 的调用System.gc()确实会启动 GC 循环。如果您使用其他 JVM,例如 J9,您必须查看他们的文档以找出答案。例如,Azul 的 JVM 有一个持续运行的垃圾收集器,因此调用System.gc()不会做任何事情

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

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

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

于 2013-05-11T10:36:33.910 回答
17

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

我强烈建议您阅读Java HotSpot Garbage Collection中提供的文档,以获取有关垃圾收集的更多详细信息。

于 2008-09-15T20:36:49.200 回答
12

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

至于何时发出手动收集,您可能想要这样做的唯一时间是当您放弃包含大量较小收集的大型收集时 - Map<String,<LinkedList>> 例如 - 您想尝试并获得性能命中然后在那里,但在大多数情况下,你不应该担心它。GC 比你更了解——可悲的是——大多数时候。

于 2008-09-15T20:25:10.117 回答
8

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

如果你调用ByteBuffer.allocateDirect()并且你得到一个 OutOfMemoryError ,你会发现这个调用在手动触发 GC 后很好。

于 2009-02-10T20:25:53.137 回答
5

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

规范需要澄清:Bug #6668279: (spec) System.gc() 应该表明我们不推荐使用并且不保证行为

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

错误 #5025281:允许 System.gc() 触发并发(不是 stop-the-world)完整收集

于 2008-09-16T18:36:52.597 回答
4

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

请注意,这些调用都不能保证做任何事情。它们只是 jvm 运行垃圾收集器的建议。是否运行 GC 取决于 JVM。所以,简短的回答:我们不知道它什么时候运行。更长的答案:如果有时间,JVM 会运行 gc。

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

于 2013-04-27T12:05:48.767 回答
2

我们永远不能强制垃圾收集。System.gc 只是建议使用 vm 进行垃圾收集,但是,该机制到底什么时候运行,没人知道,这是 JSR 规范中规定的。

于 2010-10-31T03:53:53.283 回答
2

通常,VM 会在抛出 OutOfMemoryException 之前自动进行垃圾收集,因此添加显式调用应该无济于事,除非它可能会将性能影响移到更早的时刻。

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

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

于 2009-02-10T13:20:10.290 回答
2

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

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

于 2012-07-25T12:01:22.337 回答
2

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

我目前正在从事一个涉及内存有限环境和相对大量数据的项目——有一些大数据将我的环境推到了极限,即使我能够降低内存使用量理论上它应该可以正常工作,但我仍然会收到堆空间错误——详细的 GC 选项向我显示它正在尝试垃圾收集,但无济于事。在调试器中,我可以执行 System.gc() 并且果然会有“大量”可用内存......不是很多额外的,但足够了。

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

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

尽管如此,即使我使用 System.gc(),我仍然继续使用命令行参数进行调整,并设法将我的应用程序的整体处理时间提高了相对显着的数量,尽管无法克服处理更大的数据块造成的绊脚石。话虽如此,System.gc() 是一个工具....一个非常不可靠的工具,如果您不小心使用它,您会希望它不会经常工作。

于 2011-03-07T09:00:13.667 回答
0

当运行显式 GC 很好时,我想不出一个具体的例子。

一般来说,运行显式 GC 实际上弊大于利,因为显式 gc 会触发完整的收集,因为它遍历每个对象需要更长的时间。如果这个显式 gc 最终被重复调用,它很容易导致应用程序运行缓慢,因为需要花费大量时间来运行完整的 GC。

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

于 2008-09-15T20:32:20.427 回答
0

根据 Bruce Eckel 在 Java 中的思考,显式System.gc()调用的一个用例是当您想要强制完成时,即调用finalize方法。

于 2011-09-21T04:44:57.090 回答
0

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

于 2012-07-06T09:57:38.280 回答