我知道Java中的垃圾回收是自动化的。但是我知道,如果您调用System.gc()
代码,那么JVM可能会或可能不会决定此时执行垃圾回收。这究竟如何工作?JVM看到时会根据什么基础/参数确切地决定执行(或不执行)GC System.gc()
?
在这种情况下,有任何示例是个好主意吗?
我知道Java中的垃圾回收是自动化的。但是我知道,如果您调用System.gc()
代码,那么JVM可能会或可能不会决定此时执行垃圾回收。这究竟如何工作?JVM看到时会根据什么基础/参数确切地决定执行(或不执行)GC System.gc()
?
在这种情况下,有任何示例是个好主意吗?
Answers:
实际上,它通常决定进行垃圾回收。答案取决于很多因素,例如您正在运行的JVM,它处于哪种模式以及所使用的垃圾收集算法。
我不会在您的代码中依赖它。如果JVM即将抛出OutOfMemoryError,则调用System.gc()不会停止它,因为垃圾收集器将尽力释放它,直到达到极限为止。我唯一看到它在实践中使用过的是在IDE中,它附加到用户可以单击的按钮上,但是即使在那儿它也不是很有用。
System.gc()
在视频游戏的加载屏幕中使用。那时,我真的不在乎该呼叫是否清除了所有可能清除的内容,或者什么也不做。我会,不过,喜欢它,而不是在游戏的载入画面时,“走向循环使用的对象付出的努力。”
我可以想到的唯一示例是在分析应用程序以搜索可能的内存泄漏时调用System.gc()的意义。我相信分析器会在拍摄内存快照之前调用此方法。
Java语言规范不保证您调用JVM时将启动GC System.gc()
。这就是“此时可能决定是否进行GC”的原因。
现在,如果您查看OpenJDK源代码(它是Oracle JVM的骨干),您将看到对的调用System.gc()
确实开始了一个GC周期。如果使用其他JVM(例如J9),则必须查看其文档以找出答案。例如,Azul的JVM有一个连续运行的垃圾收集器,因此调用System.gc()
不会做任何事情
其他一些答案提到在JConsole或VisualVM中启动GC。基本上,这些工具可远程调用System.gc()
。
通常,您不想从代码开始垃圾回收周期,因为它会弄乱应用程序的语义。您的应用程序执行一些业务工作,JVM负责内存管理。您应该将这些关注点分开(不要让您的应用程序执行某些内存管理,而要专注于业务)。
但是,在少数情况下,调用System.gc()
可能是可以理解的。考虑例如微基准测试。没有人希望在微基准测试期间发生GC周期。因此,您可以在每次测量之间触发GC周期,以确保每次测量都从一个空堆开始。
您无法控制Java中的GC-由VM决定。我从来没有穿过其中的情况下运行System.gc()
的需要。由于System.gc()
调用只是表明VM做垃圾回收,同时也做了完全的垃圾收集(新老两代在多代堆),那么它实际上可能造成更多的CPU周期比必要的消耗。
在某些情况下,可能会建议VM立即进行完整收集,因为您可能知道应用程序将在接下来的几分钟内处于空闲状态,然后再进行繁重的操作。例如,在应用程序启动期间初始化了许多临时对象之后(即,我只是缓存了大量信息,并且我知道一分钟左右不会有太多活动)。考虑一下诸如eclipse启动之类的IDE,它进行了大量的初始化工作,因此也许在初始化之后立即进行一次完整的gc有意义。
打电话给您要非常小心System.gc()
。调用它会给您的应用程序增加不必要的性能问题,并且不能保证实际执行收集。实际上,可以System.gc()
通过java参数禁用显式-XX:+DisableExplicitGC
。
我强烈建议您阅读Java HotSpot Garbage Collection中提供的文档,以获取有关垃圾收集的更多详细信息。
如果您使用直接内存缓冲区,那么即使您的直接内存不足,JVM也不会为您运行GC。
如果调用,ByteBuffer.allocateDirect()
并且收到OutOfMemoryError,则可以在手动触发GC后发现此调用很好。
Cleaners
直接存储器使用的捷径。即终结器线程不会释放它,因为这可能太慢。即使这样,如果要特别快地创建直接存储区域,也可能会获得OOME。解决方案是不要这样做,并在可能的地方重新使用直接存储区域。
大多数JVM将启动GC(取决于-XX:DiableExplicitGC和-XX:+ ExplicitGCInvokesConcurrent开关)。但是,规范的定义不太明确,以便以后可以更好地实现。
规范需要澄清:错误#6668279 :(规范)System.gc()应该表明我们不建议使用也不保证行为
RMI和NIO在内部使用gc方法,它们需要同步执行,这是当前正在讨论的问题:
Garbage Collection
Java
如果我们要在Desktop / laptop / server中执行用Java编码的软件,则在方面很有用。您可以致电System.gc()
或Runtime.getRuntime().gc()
在Java
。
请注意,这些调用都不保证可以执行任何操作。它们只是jvm运行垃圾收集器的建议。是否运行GC取决于JVM。因此,简短的回答:我们不知道它何时运行。更长的答案:如果有时间,JVM将运行gc。
我相信,Android同样适用。但是,这可能会降低您的系统速度。
通常,VM会在抛出OutOfMemoryException之前自动进行垃圾回收,因此添加显式调用无济于事,因为它可能会将性能降低的时间移到更早的时刻。
但是,我认为我遇到了一个可能与之相关的案例。我不确定,因为我还没有测试它是否有效果:
当您对文件进行内存映射时,我相信当没有足够大的内存块时map()调用会引发IOException。我认为,map()文件之前的垃圾回收可能有助于防止这种情况。你怎么看?
花很多时间测试各种垃圾收集设置要说很多,但是如上所述,这样做通常没有用。
我目前正在从事一个项目,该项目涉及内存受限的环境和相对大量的数据-有一些大数据将环境推向极限,即使我能够降低内存使用量也是如此从理论上讲应该可以正常工作,但我仍然会遇到堆空间错误-冗长的GC选项向我表明它正在尝试进行垃圾收集,但无济于事。在调试器中,我可以执行System.gc()并确保足够多的内存可用……没有很多额外的内存,但是足够了。
因此,我的应用程序唯一一次调用System.gc()的时候就是要进入代码段,在该段中将分配用于处理数据的大缓冲区,并且对可用内存的测试表明我没有保证拥有它。特别是,我正在研究一个1gb的环境,其中静态数据至少占用300mb,其中大部分非静态数据与执行相关,除非正在处理的数据恰好至少为100-200 MB,来源。这都是自动数据转换过程的一部分,因此从长远来看,所有数据都存在相对较短的时间。
不幸的是,尽管可以获得有关用于调整垃圾收集器的各种选项的信息,但这似乎很大程度上是一个实验过程,并且不容易获得了解如何处理这些特定情况所需的较低级别的细节。
综上所述,即使我使用System.gc(),我仍然继续使用命令行参数进行调优,尽管无法克服问题,但仍设法将应用程序的整体处理时间缩短了相当多的时间。通过处理较大的数据块而构成的绊脚石。话虽这么说,System.gc()是一个工具。。。一个非常不可靠的工具,如果您不小心使用它,则希望它不会经常工作。
如果您想知道是否System.gc()
调用了您的方法,则可以在JVM执行Garbage Collection时使用新的Java 7 update 4获得通知。
我不是100%肯定Java 7更新4中引入了GarbageCollectorMXBean类,因为在发行说明中找不到它,但是我在javaperformancetuning .com站点中找到了相关信息。
我想不出一个具体的例子来运行显式GC很好。
通常,运行显式GC实际上会带来弊大于利,因为显式gc会触发完整的收集,而收集通过每个对象所花费的时间要长得多。如果此显式gc最终被重复调用,则可能会导致应用程序运行缓慢,因为花费大量时间运行完整的GC。
或者,如果使用堆分析器检查堆,并且怀疑库组件正在调用显式GC,则可以将其关闭,方法是:在JVM参数中添加gc = -XX:+ DisableExplicitGC。
布鲁斯·埃克尔(Bruce Eckel)用Java来思考,显式System.gc()调用的一个用例是当您要强制完成时,即对finalize方法的调用。