关于java:System.gc()什么时候做

When does System.gc() do anything

我知道垃圾回收在Java中是自动化的。但我明白,如果在代码中编写EDCOX1(0),Java VM可以在运行时决定是否在该点进行垃圾回收。这是如何精确工作的?当虚拟机看到System.gc()时,它究竟基于什么基础/参数决定执行(或不执行)GC?在这种情况下,是否有一些示例可以将其放入代码中?


实际上,它通常决定进行垃圾收集。答案取决于很多因素,比如运行的是哪个JVM,它处于哪个模式,它使用的是哪个垃圾收集算法。

我不会在你的代码中依赖它。如果jvm将要抛出一个ofmemoryError,那么调用System.gc()不会停止它,因为垃圾收集器将在它达到这个极限之前尝试释放尽可能多的内存。我在实践中唯一一次看到它是在IDES中使用的,它连接到一个用户可以点击的按钮上,但即使在那里,它也没有太大的用处。


我能想到的唯一一个调用System.gc()有意义的例子是在分析应用程序以搜索可能的内存泄漏时。我相信在获取内存快照之前,配置程序会调用这个方法。


您无法控制Java中的GC——VM决定。我从来没有遇到过需要System.gc()的案件。由于System.gc()调用只是简单地建议VM进行垃圾收集,而且它还进行完全的垃圾收集(多代堆中的旧代和新代),因此它实际上可以导致消耗比需要更多的CPU周期。

在某些情况下,向虚拟机建议现在进行完全收集可能是有意义的,因为您可能知道应用程序将在接下来的几分钟内处于空闲状态,然后才进行重载提升。例如,在应用程序启动期间初始化了许多临时对象之后(即,我刚刚缓存了大量信息,我知道在一分钟左右的时间内不会有太多活动)。想想一个IDE,比如Eclipse启动——它需要做很多初始化工作,所以可能在初始化之后立即进行完整的GC是有意义的。


Java语言规范不能保证JVM在调用EDCOX1 OR 0时将启动GC。这就是为什么"可能或可能不决定在那个时候进行GC"。

现在,如果您看看OpenJDK源代码,它是OracleJVM的主干,您会发现对System.gc()的调用确实会启动一个GC周期。如果您使用另一个JVM,如J9,则必须检查它们的文档以找出答案。例如,azul的jvm有一个连续运行的垃圾收集器,因此对System.gc()的调用不会做任何事情。

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

通常,您不希望从代码开始垃圾收集循环,因为它会扰乱应用程序的语义。您的应用程序做一些业务工作,JVM负责内存管理。您应该将这些关注点分开(不要让您的应用程序做一些内存管理,而要专注于业务)。

但是,很少有情况下调用System.gc()是可以理解的。例如,考虑微基准。没有人想让GC循环发生在微基准的中间。因此,您可以在每个度量之间触发一个GC循环,以确保每个度量从一个空堆开始。


如果你打电话给System.gc(),你需要非常小心。调用它可能会给应用程序增加不必要的性能问题,并且不能保证实际执行集合。实际上可以通过Java参数EDCOX1(6)来禁用显式EDCOX1×0Ω。

我强烈推荐通过Java热点垃圾收集中的文档阅读更多关于垃圾收集的详细信息。


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

至于何时发布手动收集,您可能希望这样做的唯一时间是放弃包含大量较小收集的大型收集--a比如说,Map>,你想尝试在某个时候或者某个地方进行性能测试,但在大多数情况下,你不应该担心。GC比你更了解——遗憾的是——大多数时候。


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

如果您调用ByteBuffer.allocateDirect(),并得到一个outofmemoryer错误,您会发现在手动触发GC之后,这个调用是正常的。


大多数JVM将启动GC(取决于-xx:DiableExplicitGC和-xx:+ExplicitgCinvokesConcurrent开关)。但是,为了允许以后更好的实现,规范定义得不太好。

规范需要澄清:bug 6668279:(spec)system.gc()应该表明我们不建议使用,也不保证行为。

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

bug 5025281:允许System.gc()触发并发(而不是停止整个世界)完整集合


我们绝不能强迫垃圾收集。gc只是建议使用vm进行垃圾收集,但是,实际上,机制运行的时间,没有人知道,这是由JSR规范所规定的。


花时间测试各种垃圾收集设置有很多话要说,但是如上所述,这样做通常不有用。

我目前正在研究一个涉及内存有限环境和相对大量数据的项目——有一些大数据块将我的环境推到了极限,即使我能够降低内存使用率,以便理论上它可以正常工作,但我仍然会得到堆空间错误——详细的GC选项。向我展示了它试图收集垃圾,但没有用。在调试器中,我可以执行system.gc(),并确保有足够的"大量"可用内存……不是额外的,而是足够的。

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

不幸的是,虽然可以获得有关调整垃圾收集器的各种选项的信息,但这在很大程度上似乎是一个实验过程,而且不容易获得理解如何处理这些特定情况所需的低级细节。

尽管我使用的是system.gc(),但我仍然继续使用命令行参数进行优化,并设法将应用程序的总体处理时间提高了相当大的一部分,尽管我无法克服处理较大数据块所带来的障碍。也就是说,system.gc()是一个工具……一个非常不可靠的工具,如果你不小心使用它,你会希望它不会经常工作。


EDOCX1·1在EDOCX1·2中是很好的,如果我们正在用Java在桌面/膝上型/服务器上执行软件编码。您可以在Java中调用System.gc()Runtime.getRuntime().gc()

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

我相信,Android也是如此。但是,这可能会减慢系统的运行速度。


当运行显式GC比较好时,我无法想到具体的示例。

一般来说,运行显式GC实际上会造成比好的更多的伤害,因为显式GC将触发一个完整的集合,当它通过每个对象时,会花费更长的时间。如果这个显式GC最终被重复调用,那么很容易导致应用程序速度变慢,因为运行完整GC需要花费大量时间。

或者,如果使用堆分析器遍历堆,并且怀疑库组件正在调用显式GC,则可以将其关闭,将:gc=-xx:+disableexplicitgc添加到jvm参数中。


简而言之:

参数依赖于虚拟机。

示例用法-不能为运行时/生产应用程序考虑一个,但对于某些分析工具(如调用

1
2
3
4
5
6
7
8
// 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();


如果您想知道是否调用了EDCOX1 0调用,则当JVM执行垃圾收集时,可以使用新的Java 7更新4获取通知。

我不是100%肯定的是,在Java 7更新4中引入了GARBACKECOLCORTERMXBE类,因为我在发行说明中找不到它,但是我在JavaPrimeCutuunnCo站点找到了信息。


通常,在抛出OutOfMemoryException之前,VM会自动执行垃圾收集,因此添加显式调用不应该有帮助,除非它可能会将性能影响移动到更早的时间。

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

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


根据Bruce Eckel的Java思想,显式系统.gc-()调用的一个用例是强制终结,即调用终结方法。


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