【问题标题】:How to force a first generation GC in Java?如何在 Java 中强制进行第一代 GC?
【发布时间】:2021-01-09 16:34:54
【问题描述】:

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

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

【问题讨论】:

  • 不,这是不可能的。此外,对 System.gc() 的调用只是对 JVM 的建议,即应该执行 gc,尽管在实践中,我不知道有任何 JVM 没有在 System.gc()call 上运行 gc。
  • @Erik 但这是一个触发的并发标记阶段,它可能会产生完全为零的实际垃圾回收。
  • @Eugene 我考虑过,但这种情况更像是一个愿望,而不是你可以依赖的东西,所以它似乎不值得一提。但是,我确实想知道所描述的用例。如果考虑到所述背景,gc 时间可能会成为问题,那么我们在这里谈论的堆有多大?
  • 因为我们使用内存消耗操作,所以堆可能非常大。许多 GB。然后 GC 可能需要更多的时间。这也是检查频率的问题。

标签: java memory garbage-collection mxbean


【解决方案1】:

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

更长的答案:

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

如果您查看此 API,您可以看到 JVM 可以调用以触发垃圾收集的虚拟方法。事实证明,它们共有三个,但它们都调用了完整的垃圾回收。因此,即使您尝试从使用 JNI 调用的本机代码中触发 GC,您最终还是会执行完整的 GC。

可以下载 OpenJDK 源代码,修改 CollectedHeap API 和堆实现,以便触发新一代 GC,并构建具有所需功能的自定义 JVM。您甚至可以分发二进制文件只要您遵守 OpenJDK“GPLv2 + Classpath 例外”许可的条款。然而,这将是一项巨大的事业。


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

触发 GC 几乎总是一个坏主意。作为一般规则,堆本身知道运行 GC 的最佳(最有效)时间,以满足您在 GC 调整选项中配置的目标。最好的策略是不干涉。只需让 JVM 处理时间。

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

在生产代码中干预(通过调用System.gc())的唯一合理的合理理由是应用程序是否存在知道可以降低效率的点。一个经典的例子是一个游戏,GC 暂停在正常游戏过程中是有害的,但在(例如)加载下一个“关卡”时它们是可以的。所以在加载关卡后触发 GC 可能是有益的。

从您的问题中并不清楚您通过强制 GC 运行来实现的目标。但我的建议是阅读 Java GC 调优,设置 JVM 选项,然后让 JVM 来管理堆。

【讨论】:

  • 谢谢。问题是,如果我在运行 GC 之前停止所有操作,那么我可以等待几天而不会发生 GC。如果我在内存不足的情况下继续,那么它将导致 OutOfMemoryError 可能对服务器自身产生致命的结果。
  • 好的。所以这是你选择垃圾收集器的问题。在最新版本的 Java 中,有一些收集器被设计为在非常大的堆中表现良好。看看 Z 和 Shenandoah 收藏家; medium.com/@hasithalgamge/…
【解决方案2】:

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

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 ) {
   ...
}

【讨论】:

    猜你喜欢
    • 2017-01-06
    • 1970-01-01
    • 2013-03-25
    • 2021-03-03
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    相关资源
    最近更新 更多