java - 即使 HotSpot 中没有 CMS 的 Full GC,如何减少老年代的大小?

标签 java garbage-collection jvm jvm-hotspot

在“Visual GC”选项卡中查看 VisualVM 时,我注意到,对于使用并发标记和清除 (CMS) 收集器运行的应用程序,老年代大小可能会减小(按绝对值计算),即使没有 Full GC 正在启动。

我觉得这不可能吗?正如您在此图表中所看到的,即使 Old Gen 收集计数 = 4,堆的演变也有起有落:

enter image description here

我预计要么会看到 4 次减少(每次 Full GC 减少一次),要么想到的唯一理论是 Full GC 需要永远执行,而不是一次看到可用内存大幅下降,我看到它正在小批量地慢慢发布。但 1 分 18 秒的总收集时间对于这个理论来说似乎太短了。

以下是我的应用程序设置(在本例中,应用程序是 CLion,这些是其默认设置,堆大小除外):

-Xss2m
-Xms256m
-Xmx4g
-XX:NewSize=128m
-XX:MaxNewSize=128m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-XX:CICompilerCount=2

最佳答案

嗯,经过一番挖掘,查看 HotSpot 的源代码并查看 GC 日志,显示的行为的原因似乎是显示为“旧一代集合”的内容并不是真正的 CMS 集合(这些集合似乎比比皆是) ,从应用程序一开始),但是(滑动)Mark & Compact GC。

当 JVM 得出结论,后续年轻代 GC 甚至再次运行 CMS 不会回收新内存时,将触发(滑动)标记和压缩。就在调用它并因 OoM 错误退出之前,它仍然会尝试停止整个应用程序并运行 M&C——由于 CMS 是一种非压缩算法,因此仍然有可能通过重新排列内存中的对象来提供新内存以更紧凑的方式。这将是 STW 操作。

我是如何得出这个结论的?好吧,如果您在跟踪级别运行 GC 日志,您会发现时不时会收到一些 CMS:MSC (并发标记与清除:标记-清除-压缩)语句,这些语句似乎与 JVisualVM 中 OldGen 的更新一致。下面是触发该语句的 HotSpot 代码:

// A work method used by the foreground collector to do
// a mark-sweep-compact.
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
  CMSHeap* heap = CMSHeap::heap();

  STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
  gc_timer->register_gc_start();

  SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
  gc_tracer->report_gc_start(heap->gc_cause(), gc_timer->gc_start());

  heap->pre_full_gc_dump(gc_timer);

  GCTraceTime(Trace, gc, phases) t("CMS:MSC");

实际上,通过仔细查看日志,您可以看到这确实是一个 Mark Compact 正在发生(我在这里过滤掉了 INFO 级别以下的任何内容,因此原始的 CMS:MSC 语句获胜不出现):

GC(257) Pause Full (Allocation Failure)
GC(257) Phase 1: Mark live objects                       <-- marking
GC(257) Phase 1: Mark live objects 4675.159ms
GC(257) Phase 2: Compute new object addresses
GC(257) Phase 2: Compute new object addresses 1123.827ms
GC(257) Phase 3: Adjust pointers
GC(257) Phase 3: Adjust pointers 2906.019ms
GC(257) Phase 4: Move objects                            <-- compacting
GC(257) Phase 4: Move objects 630.602ms
GC(257) ParNew: 118016K->116364K(118016K)
GC(257) CMS: 1966080K->1966079K(1966080K)
GC(257) Metaspace: 181716K->181716K(1214464K)
GC(257) Pause Full (Allocation Failure) 2035M->2033M(2035M) 16031.595ms
GC(257) User=18.01s Sys=0.15s Real=16.04s

关于java - 即使 HotSpot 中没有 CMS 的 Full GC,如何减少老年代的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59483893/

相关文章:

java - 混淆以隐藏某些算法

java - 在 apache poi 中每 10 个项目后插入新行

java - 为什么不建议在 JSP 中使用 JavaScript?

java - 监控IntelliJ 2018.03时出现这么多Major GC?

ruby-on-rails - Ruby 1.9 垃圾收集器,GC.disable/enable

Git:Git 什么时候进行垃圾回收?

java - 内存游戏失败

java - 堆转储与可视化虚拟机中的内存分析

java - 如果您不在 java 8 rcp 应用程序中指定 maxmetaspace 参数,会发生什么情况?

java - jcmd - `jcmd VM.flags -all` 最后一列的含义