【问题标题】:Hotspot JVM - G1GC Heap resizing issueHotspot JVM - G1GC 堆大小调整问题
【发布时间】:2017-01-05 14:54:13
【问题描述】:

我最近正在测试一个并发负载相对较高的演示应用程序。该应用程序是一个 java 应用程序,在 Hotspot JVM (1.8.0_111) 上运行。

使用 4G 堆和并行吞吐量收集器,我可以获得大约 400 TPS 的最大吞吐量。吞吐量图表(作为负载的函数)如下所示。

因为 Oracle 建议对大于 4G 的堆大小使用 G1GC,所以我想尝试 G1,看看这是否对我的应用程序吞吐量有任何好处。

令我惊讶的是,使用 G1GC,我看到了以下吞吐量趋势。

我真的很惊讶,并决定深入了解这里发生了什么。这是我发现的。

我看到,最初,在 4G 堆中,1.5G 分配给老一代区域,2.5G 分配给伊甸区域。但是随着时间的推移,老一代不再适合 1.5G,堆的大小会被调整。这似乎无伤大雅。但问题似乎在于调整大小的方式。

现在所有 4G 都分配给老一代区域,几乎没有分配给伊甸园区域。现在,当需要将某些东西分配给伊甸园时,堆会再次调整大小。这已成为新常态,堆会反复调整大小,从而给应用程序带来巨大的性能成本。

有没有人在使用 G1GC 之前注意到这一点?有什么建议可以协商这个问题吗?

下面是带有 JVM 选项的启动命令行。

java -server -Xms4096m -Xmx4096m -XX:MetaspaceSize=100m -XX:MaxMetaspaceSize=100m -XX:MaxDirectMemorySize=512m -XX:MinMetaspaceFreeRatio=0 -XX:MaxMetaspaceFreeRatio=100 -XX:CompressedClassSpaceSize=20m -XX:InitialCodeCacheSize=50m -XX:ReservedCodeCacheSize=50m -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/tmp -Xloggc:/servers/logs/gc.log.2017-01-05-085234 -Djava.awt.headless=true -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Dio.netty.leakDetectionLevel=simple -XX:MaxDirectMemorySize=512m -Dadmin.connectors.http.port=9000 -Dproxy.connectors.http.port=8080 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8654 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -server -cp ...

JVM 选项:

-server 
-Xms4096m 
-Xmx4096m 
-XX:MetaspaceSize=100m 
-XX:MaxMetaspaceSize=100m 
-XX:MaxDirectMemorySize=512m 
-XX:MinMetaspaceFreeRatio=0 
-XX:MaxMetaspaceFreeRatio=100 
-XX:CompressedClassSpaceSize=20m 
-XX:InitialCodeCacheSize=50m 
-XX:ReservedCodeCacheSize=50m 
-XX:+AlwaysPreTouch 
-XX:+DisableExplicitGC 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/var/tmp 
-Xloggc:/servers/logs/gc.log.2017-01-05-085234 
-Djava.awt.headless=true 
-XX:+UnlockCommercialFeatures 
-XX:+FlightRecorder 
-Dio.netty.leakDetectionLevel=simple 
-XX:MaxDirectMemorySize=512m 
-Dadmin.connectors.http.port=9000 
-Dproxy.connectors.http.port=8080 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=8654 
-Dcom.sun.management.jmxremote.local.only=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-server 
-cp ...

请查找 gc 日志here

【问题讨论】:

  • 请问您可以分享您在应用程序启动期间设置的所有参数吗? docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/…
  • @SauliusNext 我现在已将参数列表添加到问题中。对于G1GC,唯一的区别是添加了-XX:+UseG1GC
  • 由于您已经启用了 GC 日志记录,因此您应该附加一个足够长的感兴趣时间段的 GC 日志。
  • @SasidharSekar 我已代表您提交了一个问题bugs.openjdk.java.net/browse/JDK-8172354。请查看 Oracle 高级 GC 工程师“Thomas Schatzl”提供的建议,如果您需要进一步说明,请告诉我。
  • 谢谢@Fairoz 这澄清了很多事情。我会尝试这些建议,看看情况如何改善。

标签: java jvm heap-memory hotspot g1gc


【解决方案1】:

似乎有以下两种GC原因:

  • [GC pause (G1 Humongous Allocation) (young) (initial-mark)
  • [GC 暂停(G1 疏散暂停)(年轻)(空间耗尽)

巨大的分配需要老一代的空间,空间耗尽会增加年轻一代的大小。他们基本上是在互相竞争。

看起来您分配大量对象(> 1/2 G1 区域大小)的速度比 IHOP 发起的并发周期收集它们的速度要快。

您可以尝试增加区域大小。如果它们是大型原始数组(即不是参考数组),那么实验性的 eager reclaim feature 也可能会有所帮助。

【讨论】:

  • 是的。事实上,我的应用程序确实分配了很多巨大的对象。不幸的是,您所指的急切回收功能似乎仅适用于 OpenJDK(我使用的是 Hotspot JVM)。但是,在阅读了您和@sauliusNext 提到的 cmets 之后,我想我将尝试使用以下选项来看看它有什么帮助。 -XX:MaxGCPauseMillis -XX:G1MixedGCLiveThresholdPercent= -XX:G1MixedGCCountTarget= -XX:G1OldCSetRegionThresholdPercent=
  • 在整个练习结束时,我意识到您增加区域大小的建议解决了我的问题。谢谢:-)
猜你喜欢
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2021-09-20
  • 2011-07-05
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多