如何在Java中强制生成第一代GC



使用System.gc()方法可以强制执行完整的GC。这很贵。是否有只强制第一代GC的选项?我的应用程序目前正在Java 11上运行。我在想类似MemoryPoolMXBean的东西。

背景:我想启动一个消耗大量内存的任务,如果可用内存低于所需内存,那么我想知道我是否可以在没有风险的情况下启动它,或者我应该稍后尝试或将缓存交换到磁盘。实际上,我想知道第一次GC之后的空闲内存。我们的分析表明,在大多数情况下(>99%(,这就足够了。

简单的答案是没有支持的方法来做到这一点。它是System.gc()或者什么都没有。

更长的答案:

我搜索了JVM源代码,找到了C++CollectedHeapAPI。(如果您感兴趣的话,它位于"src/hotspot/share/gc/shared/collectedHeap.hpp"中。(这是JVM配置的堆与JVM其余部分之间的内部接口。

看看这个API,就可以看到JVM可以调用的虚拟方法来触发垃圾回收。事实证明,它们有三个,但它们都调用了一个完整的垃圾回收。因此,即使您试图从使用JNI调用的本机代码中触发GC,您最终也会执行完整的GC。

可以下载OpenJDK源代码,修改CollectedHeapAPI和堆实现,以便触发新一代GC,并构建具有所需功能的自定义JVM。如果您遵守OpenJDK的条款,您甚至可以分发二进制文件;GPLv2+类路径异常";许可证。然而,这将是一项巨大的任务


但我认为你的问题被误导了。

触发GC几乎总是一个坏主意。一般来说,堆本身知道运行GC的最佳(最有效(时间,以实现您在GC调优选项中配置的目标。最好的策略是不干涉。只需让JVM负责时间安排。

根本问题是,gc()运行的大部分成本都用于处理非垃圾对象;即需要由收集器从一个空间复制到另一个空间的对象。留下的任何垃圾(通常(都将被归零。因此,运行收集最符合人体工程学的时间是垃圾与非垃圾的比例(在收集的空间中(尽可能高时;即当它接近满时。

在生产代码中干扰(通过调用System.gc()(的唯一合理理由是,如果应用程序在某些方面知道效率低下是可以的。一个经典的例子是GC暂停在正常游戏期间是有害的,但当(例如(加载下一个"游戏"时,它们是可以的;电平";。因此,在加载一个级别之后触发GC可能是有益的。

从你的问题和评论中还不清楚你通过强制GC运行来实现什么。但我的建议是阅读Java GC调优,设置JVM选项,然后让JVM来管理堆。

我使用以下代码来检查是否有足够的内存用于内存意图操作:

int requiredMemory = ...;
// force a first generation GC
try {
byte[] ram = new byte[requiredMemory];
requiredMemory = ram[0]; // should be ever 0 and prevent optimize through JIT because the allocated array works outside of the block
} catch( OutOfMemoryError ex ) {
// ignore, uncritical because it occur through a large block
}
if( requiredMemory == 0 ) {
...
}

相关内容

  • 没有找到相关文章

最新更新