6

我一直在我的一个项目中使用 Java 8 (Oracle JVM) 试验 G1GC。我的 GC 标志实际上是:

-Xms64m
-Xmx1024m
-XX:+UseG1GC
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-Xloggc:/tmp/gc.log
-XX:+PrintAdaptiveSizePolicy

我观察到堆比我拥有的实时数据量大得多。GC 日志显示了我认为的根本原因:

[G1Ergonomics (Heap Sizing) attempt heap expansion, reason: recent GC overhead higher than threshold after GC, recent GC overhead: 10.17 %, threshold: 10.00 %, uncommitted: 811597824 bytes, calculated expansion amount: 162319564 bytes (20.00 %)]

实际上,我的应用程序正在生成大量垃圾,因此花费在 GC 上的时间比例高于 10%,因此 G1 的人体工程学增加了堆大小。


使用 Parallel 收集器可以调整此阈值-XX:GCTimeRatio(吞吐量目标),但从我在文档中看到的内容来看,G1 没有等效标志。

对于并行收集器,Java SE 提供了两个基于实现应用程序指定行为的垃圾收集调优参数:最大暂停时间目标和应用程序吞吐量目标;请参阅并行收集器部分。(这两个选项在其他收集器中不可用。)请注意,这些行为并不总是能够满足。

我的问题是,除了降低最大堆大小之外,我如何调整 G1GC 以获得更小的内存占用?

在日志中,没有证据表明我超出了最大暂停时间目标,并且确实增加了这一目标并不能解决问题。


这可能是这个问题的欺骗:哪个 JVM Flag 设置了 G1Ergonomics 日志中提到的 GC 开销阈值?,但似乎已接受了不正确的答案。(或者也许它只对旧版本的 JVM 是正确的。)

4

2 回答 2

4

概述:

  • 这篇 Oracle 文章(1) 中,您可以找到 G1 最重要的标志(包括-XX:MaxGCPauseMillis)。

  • 此错误报告表明该GCTimeRatio标志也在 G1 中使用。

  • 另请参阅此相关问题和答案(2)。

  • 我假设您应该能够通过设置-XX:MaxGCPauseMillis更高的值来解决这个问题,或者如果您知道您的应用程序会产生很多(年轻)垃圾,您可以使用有关年轻代大小的设置。编辑:好的,对此要非常小心,(1)状态:*年轻代大小*:避免使用 -Xmn 选项或任何或其他相关选项(例如 -XX:NewRatio)显式设置年轻代大小。固定年轻代的大小会覆盖目标暂停时间目标。


(1)

重要默认值:

G1 GC 是一种自适应垃圾收集器,其默认设置使其无需修改即可高效工作。这是重要选项及其默认值的列表。此列表适用于最新的 Java HotSpot VM,内部版本 24。您可以通过在 JVM 命令行上输入以下带有更改设置的选项来调整和调整 G1 GC 以满足您的应用程序性能需求。

  • -XX:G1HeapRegionSize=n

设置 G1 区域的大小。该值将是 2 的幂,范围可以从 1MB 到 32MB。目标是基于最小 Java 堆大小拥有大约 2048 个区域。

  • -XX:MaxGCPauseMillis=200

为所需的最大暂停时间设置目标值。默认值为 200 毫秒。指定的值不适应您的堆大小。

  • -XX:G1NewSizePercent=5

设置堆的百分比以用作年轻代大小的最小值。默认值为 Java 堆的 5%。这是一个实验标志。有关示例,请参阅“如何解锁实验性 VM 标志”。此设置替换 -XX:DefaultMinNewGenPercent 设置。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:G1MaxNewSizePercent=60

设置堆大小的百分比以用作年轻代大小的最大值。默认值为 Java 堆的 60%。这是一个实验标志。有关示例,请参阅“如何解锁实验性 VM 标志”。此设置替换 -XX:DefaultMaxNewGenPercent 设置。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:ParallelGCThreads=n

设置 STW 工作线程的值。将 n 的值设置为逻辑处理器的数量。n 的值与最大为 8 的逻辑处理器的数量相同。

如果有超过 8 个逻辑处理器,则将 n 的值设置为逻辑处理器的大约 5/8。这在大多数情况下都有效,但较大的 SPARC 系统除外,其中 n 的值可能约为逻辑处理器的 5/16。

  • -XX:ConcGCThreads=n

设置并行标记线程的数量。将 n 设置为并行垃圾回收线程 (ParallelGCThreads) 数量的大约 1/4。

  • -XX:InitiatingHeapOccupancyPercent=45

设置触发标记周期的 Java 堆占用阈值。默认占用率为整个 Java 堆的 45%。

  • -XX:G1MixedGCLiveThresholdPercent=65

设置要包含在混合垃圾回收周期中的旧区域的占用阈值。默认占用率为 65%。这是一个实验标志。有关示例,请参阅“如何解锁实验性 VM 标志”。此设置替换 -XX:G1OldCSetRegionLiveThresholdPercent 设置。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:G1HeapWastePercent=10

设置您愿意浪费的堆百分比。当可回收百分比小于堆浪费百分比时,Java HotSpot VM 不会启动混合垃圾回收周期。默认值为 10%。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:G1MixedGCCountTarget=8

设置标记周期后混合垃圾收集的目标数量,以收集最多具有 G1MixedGCLiveThresholdPercent 实时数据的旧区域。默认为 8 次混合垃圾回收。混合收藏的目标是在这个目标数字内。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:G1OldCSetRegionThresholdPercent=10

设置在混合垃圾收集周期期间要收集的旧区域数量的上限。默认值为 Java 堆的 10%。此设置在 Java HotSpot VM 内部版本 23 中不可用。

  • -XX:G1ReservePercent=10

设置保留内存的百分比以保持空闲,以降低 to-space 溢出的风险。默认值为 10%。当您增加或减少百分比时,请确保将总 Java 堆调整相同的数量。此设置在 Java HotSpot VM 内部版本 23 中不可用。


(2)

我的猜测是这recent GC overhead higher than threshold推动了 G1 的决定。您可以通过设置来放松它-XX:GCTimeRatio=4,这将允许它相对于 GCing 的应用程序时间占用 20% 的 CPU 周期,而不是 10%。

如果这太多了,你应该要么

  • 允许它使用更多的 CPU 内核——这将更容易满足其暂停时间目标,这反过来意味着它可以将收集延迟更长的时间,从而更容易满足吞吐量目标。是的,这确实意味着使用更多内核实际上可以使用更少的 CPU 周期。

  • 放松暂停时间目标,因此它必须减少收集频率

于 2016-04-06T14:28:33.627 回答
1

经过进一步调查,G1 的人体工程学似乎确实尊重-XX:GCTimeRatio,尽管文档说了什么。

于 2016-04-06T13:09:24.427 回答