【问题标题】:Java garbage collection: minor, major, fullJava 垃圾回收:minor、major、full
【发布时间】:2014-09-12 01:10:52
【问题描述】:

我正在尝试在大型企业 Java 应用程序中进行垃圾收集。我有 GC 日志并开始使用各种工具查看它们 - 这里的屏幕截图是使用 GCViewer 完成的。 (遗憾的是没有日志包含更详细的 GC 信息...)

我还在阅读我们正在使用的 Java Hotspot VM 垃圾收集。

但我还是有点困惑:下面是 GC 图的放大部分截图。

这里发生了三件事:

  1. 蓝线有“小曲折”(您几乎看不到):据我了解,这些是 Young 空间中发生的 次要 gc 循环。
  2. 有一个黑条,是阻塞10s的full GC,在日志中可以看到:

    1751585.394: [Full GC 1433326K->660045K(1552832K), 10.1157600 secs]
    
  3. 然后是蓝线的“大曲折”(表现在左边的水滴中)。 这让我很困惑。

模式 #3 的日志没有将其标记为完全 GC,但看起来与其他类似...

    1749795.648: [GC 1299871K(1552832K), 0.0402933 secs]
  • 那么这也是次要 GC 吗?
  • 如果是,为什么会同时发生两种不同模式的次要垃圾收集(#1 和 #3)?
  • 或者在 Young 空间中的 Minor GC 和 Tenured 中的 Full GC 之间还有其他什么关系?

编辑。一些附加信息:
使用的 GC:并发 Mark-Sweep GC
吞吐量为 93.8 %
最长暂停:10.116 秒
暂停时间:6.21%

【问题讨论】:

  • 我怀疑完整的 gc 需要 0.0402933 秒。对我来说,这仍然是次要的
  • 我也认为这是另一个小收藏。是否有可能只是大量的短期对象在那时可供收集?

标签: java garbage-collection


【解决方案1】:

Java 的分代垃圾收集器有几种不同的垃圾收集“种类”。正如您所提到的,“小曲折”是年轻空间中的次要收集,黑条将是完整的垃圾收集。为简单起见,我将仅描述正在发生的事情中最重要的部分。

年轻代被划分为一个“伊甸园”空间一个或多个“幸存者”空间。在其中一个小曲折过程中,伊甸园空间中的死物被移除,活物被移动到幸存者空间之一。这是一个非常快速的操作,因为 weak 世代假设表明大多数对象都是短暂的。幸存者空间的后续扫描可能会将仍然活着的对象从 幸存者 空间移动到 tenured 代。这仍被视为次要集合。

我怀疑你在第一次大跌中看到的实际上是从幸存者一代到终身一代的“提升”。

tenured 代是指所有不够年轻而不能进入年轻代的东西(这意味着,与许多其他 GC 选项一样,是可调整的)。终身代比年轻代大得多,因此需要大量的时间来清扫。当您谈论“完整”垃圾回收时,这是指对老年代(除了年轻一代)的扫描。

CMS 垃圾收集器在其所做的大部分事情上同时运行,但仍需要stop the world 用于年轻代和终身代的标记操作。 CMS 收集器在这方面应该非常快,即使对于大堆也是如此。但是,还有另一种 CMS 停止世界的情况:concurrent mode failure

暂停的第二次大幅下降可能是由于这个原因,当tenured generation太满时会发生这种情况。你可以调整tenured generation的大小和其他参数来避免这些。

【讨论】:

  • 酷,谢谢。我假设完整的 GC 块是并发模式故障,但由于缺少 GC 日志详细级别而无法验证它。关于下降是“促销”:这将如何导致下降?幸存者(年轻的)和终身的都在已提交的堆中,那么堆怎么会下降得如此显着(顺便说一下,下降的数量与在完整 GC 期间观察到的数量大致相同)?
  • @fgysin 只是猜测:GC 必须知道哪些年轻对象可以从永久空间中访问(请参阅write barrier)。也许对幸存者也是如此,然后只需要提升一些幸存者,其余的则被丢弃。
  • @fgysin 我想,我现在明白了。两个大水滴都是主要系列。左边的速度非常快,因为大多数工作都是同时完成的,所以没有明显的停顿。粗黑条对应一个问题,可能是并发模式失败,但也可能是线程需要很长时间才能到达安全点。
【解决方案2】:

我怀疑这是并发扫描。要确认,必须使用以下监控

-verbose:gc -XX:+PrintGCDetails

假设图表显示年轻 + 终身代,这不能像乔纳森提到的那样从幸存者代提升到终身代。

【讨论】:

  • 我很确定它是一个 CMS,因为这是 jmap -heap 向我展示的:using parallel threads in the new generation. using thread-local object allocation. Concurrent Mark-Sweep GC
【解决方案3】:

根据您拥有的日志,我会说:

1) 这是一个次要集合。正如@Eugene 上面所说,它很短,并且没有标记为full-gc。

2) 此时,您的应用程序中有两种短期对象。一些非常短暂的,它们“持续”了两个小曲折之间的时间。还有一些寿命较长的,它们的寿命还不够长,无法晋升为终身代,并且在令人困惑的次要收集之前的某个时间点有资格获得 gabage-collection。

可能还有其他解释,但我不相信你能从你所拥有的情况中看出这一点。

如果您对此感到担忧(或者如果您只是好奇),我会启用更详细的 gc 日志记录,并使用您的访问日志等日志来尝试将应用程序活动与丢弃相关联。

【讨论】:

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