5

我最近正在测试一个并发负载相对较高的演示应用程序。该应用程序是一个 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 日志

4

1 回答 1

1

以下两个GC原因似乎有很多:

  • [GC pause (G1 Humongous Allocation) (young) (initial-mark)
  • [GC pause (G1 Evacuation Pause) (young) (to-space耗尽)

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

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

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

于 2017-01-06T18:03:08.833 回答