System.gc()
和Runtime.gc()
的javadoc表明,可以配置JVM忽略这些方法的调用,例如使用-XX:+DisableExplicitGC
JVM选项。但是,默认情况下它们不是这样配置的(至少在当前版本的Oracle和OpenJDK Java中)。因此,默认情况下这些调用会执行某些操作。System.gc()
来获得保证的GC有什么问题?”当您能够通过gc()
调用调用垃圾收集器时,它通常会进行完整的收集。这很昂贵,特别是当非垃圾数据量很大时。不幸的是,很多Java程序员没有意识到这一点。因此,(据我所知)忽略显式的gc()
调用的JVM选项的主要原因是为了减轻程序员滥用该方法的潜在灾难性能影响。System.gc()
调用触发GC,则最好的建议是确保您的JVM选项中不包括-XX:+DisableExplicitGC
。请阅读Oracle手册条目以获取更多信息。来自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在重要时刻运行。
基本上,你说得没错,jvm并不能保证在你调用System.gc()
后立即启动gc。不过,gc可以记录你现在想要进行垃圾回收的意愿,并实际运行。
这取决于jvm,但就我所知,热点jvm实际上会在System.gc()
或Runtime.gc()
之后运行gc,至少大部分时间都是这样的。
因此,我认为没有至少一种方法来建议虚拟机运行gc将是一个错误。可能会有不同的虚拟机实现,如果有一种虚拟机希望提供调用gc的可能性,并保证在此类调用之后它会被实际运行,那么这并不会违反规范,而且对某些情况可能会很有用,正如我已经提到的,热点vm很可能不会忽略这个调用。
如果有人想掌控垃圾回收(这对旧版JVM有效),则提供了这些方法,但是特别是现代JVM实现具有高度优化的垃圾收集器,因此总是明智将垃圾部分留给JVM。我们的工作已经被现代JVM实现简化,因此我们只需专注于Java代码。
你说得对,当没有使用情况时,不应该提供gc()
调用。我可以想到至少一个正面和两个负面的使用显式GC调用的点:
如果您正在构建一个应用程序,其中您几乎无法控制JVM选项,并希望从代码内部实现一些神级调优,那么您可以使用显式调用。但请放心,这不是一个魔法调用,可以在您突然期望低负载的情况下完成GC。您可能需要付出很多努力来实现这一点,例如估计GC的响应能力、要收集的内存量等。
System.gc()
或Runtime.getRuntime().gc()
可能会作为提醒或建议,但是否这样做完全取决于JVM。相反,它可能根本不会在看到这样的请求时执行任何操作。参考:Oracle Java
话虽如此,通常还是避免使用,因为GC是可以通过外部JVM选项来控制和处理的,而不是通过代码本身来处理。例如:-XX:-DisableExplicitGC