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