Java中垃圾收集器方法的作用是什么?

3
如果调用System.gc()或Runtime.gc()方法,不能保证一定会进行垃圾回收。是否执行垃圾回收取决于JVM。那么这些方法有什么意义呢?

9
就像你的妻子告诉你要倒掉垃圾一样,即使她不说你也可能会自己倒掉,但即便她说了你也可能不一定立刻去倒。然而她还是会告诉你,那么她告诉你的意义在哪里呢?你可以把它看作是一个提醒去倒垃圾。 - Eran
这些方法非常古老,而Java在向后兼容方面有相当不错的记录。尽管它们已经不再是很有用的方法,但删除它们也没有太多优势。 - Kayaman
5个回答

4
System.gc()Runtime.gc()的javadoc表明,可以配置JVM忽略这些方法的调用,例如使用-XX:+DisableExplicitGC JVM选项。但是,默认情况下它们不是这样配置的(至少在当前版本的Oracle和OpenJDK Java中)。因此,默认情况下这些调用会执行某些操作。
话虽如此,在大多数情况下,直接调用垃圾收集器都是一个坏主意。只有以下几种情况才是合理的:
- 如果您正在尝试调查或测试GC相关代码的行为,例如finalizers。 - 如果您想在用户不会注意到的时间运行GC,以避免在不方便的时候出现GC暂停。
引用一段话:“我不明白通过请求System.gc()来获得保证的GC有什么问题?”当您能够通过gc()调用调用垃圾收集器时,它通常会进行完整的收集。这很昂贵,特别是当非垃圾数据量很大时。不幸的是,很多Java程序员没有意识到这一点。因此,(据我所知)忽略显式的gc()调用的JVM选项的主要原因是为了减轻程序员滥用该方法的潜在灾难性能影响。
如果您确实希望您的System.gc()调用触发GC,则最好的建议是确保您的JVM选项中不包括-XX:+DisableExplicitGC。请阅读Oracle手册条目以获取更多信息。
大部分垃圾收集的运行时成本都在跟踪和复制仍然可达的对象图中。如果您告诉收集器在需要之前运行,那么会降低其效率。相比之下,JVM本身知道堆何时已满或接近足够需要进行收集。实际上,它可以针对两个不同的要求进行优化:最大化吞吐量或最小化GC暂停时间。

我理解你的观点,但是我不明白在请求System.gc()时提供保证的GC有什么问题?这样我可以更好地设计事物并期望它按照我想要的方式工作...也许它会付出一些代价(性能),但如果它能够保证在我请求的时间运行,我将能够更好地处理它...我可以在用户不会注意到的时候运行那个GC,就像你说的那样。 - Addy

2

来自Java 7文档

public static void gc()

运行垃圾回收器。

调用gc方法建议Java虚拟机花费一些力气回收未使用的对象,以便使它们当前所占用的内存可用于快速重用。当从方法调用返回控制权时,Java虚拟机已经尽最大努力从所有丢弃的对象中回收空间。

调用System.gc()实际上相当于调用:

Runtime.getRuntime().gc()

因此,本质上,这是对GC启发式算法的建议,现在是释放一些内存的好时机。例如,假设您正在编写一个游戏,其中帧速率锁定为60FPS。每帧有16.6(当然是重复的)毫秒的预算。假设您的帧仅需要5ms才能运行。通常,您将使用Thread.sleep等待剩余时间。但是,您可以选择先调用System.gc(),告诉VM“嘿,我有一些额外的时间——请随意在我等待时清理”。当然,您无法保证垃圾回收将少于您剩余的11.6MS!但是,如果小心使用,它可以帮助您的内存使用情况,并防止垃圾回收在不重要的时间发生。类似的原则适用于其他类型的应用程序——基本上,如果您知道您的应用程序将有一些停机时间,您可以使用System.gc()告诉VM,并希望防止GC在重要时刻运行。


0

基本上,你说得没错,jvm并不能保证在你调用System.gc()后立即启动gc。不过,gc可以记录你现在想要进行垃圾回收的意愿,并实际运行。

这取决于jvm,但就我所知,热点jvm实际上会在System.gc()Runtime.gc()之后运行gc,至少大部分时间都是这样的。

因此,我认为没有至少一种方法来建议虚拟机运行gc将是一个错误。可能会有不同的虚拟机实现,如果有一种虚拟机希望提供调用gc的可能性,并保证在此类调用之后它会被实际运行,那么这并不会违反规范,而且对某些情况可能会很有用,正如我已经提到的,热点vm很可能不会忽略这个调用。


0

如果有人想掌控垃圾回收(这对旧版JVM有效),则提供了这些方法,但是特别是现代JVM实现具有高度优化的垃圾收集器,因此总是明智将垃圾部分留给JVM。我们的工作已经被现代JVM实现简化,因此我们只需专注于Java代码。


0

你说得对,当没有使用情况时,不应该提供gc()调用。我可以想到至少一个正面和两个负面的使用显式GC调用的点:

  1. 如果您正在构建一个应用程序,其中您几乎无法控制JVM选项,并希望从代码内部实现一些神级调优,那么您可以使用显式调用。但请放心,这不是一个魔法调用,可以在您突然期望低负载的情况下完成GC。您可能需要付出很多努力来实现这一点,例如估计GC的响应能力、要收集的内存量等。

  2. System.gc()Runtime.getRuntime().gc()可能会作为提醒或建议,但是否这样做完全取决于JVM。相反,它可能根本不会在看到这样的请求时执行任何操作。参考:Oracle Java

  3. 话虽如此,通常还是避免使用,因为GC是可以通过外部JVM选项来控制和处理的,而不是通过代码本身来处理。例如:-XX:-DisableExplicitGC


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