Java 热点JVM-G1GC堆大小调整问题

Java 热点JVM-G1GC堆大小调整问题,java,jvm,heap,hotspot,g1gc,Java,Jvm,Heap,Hotspot,G1gc,我最近在测试一个并发负载相对较高的演示应用程序。该应用程序是一个java应用程序,运行在Hotspot JVM(1.8.0_111)上 使用4G堆和并行吞吐量收集器,我可以获得大约400 TPS的最大吞吐量。吞吐量图(作为负载的函数)如下所示 因为Oracle建议对大于4G的堆大小使用G1GC,所以我想试试G1,看看这是否对我的应用程序吞吐量有任何好处 令我惊讶的是,对于G1GC,我看到了低于吞吐量的趋势 我真的很惊讶,决定深入研究,看看这里发生了什么。这就是我发现的 我看到,最初,在4G

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

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

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

令我惊讶的是,对于G1GC,我看到了低于吞吐量的趋势

我真的很惊讶,决定深入研究,看看这里发生了什么。这就是我发现的

我看到,最初,在4G堆中,1.5G分配给老gen区域,2.5G分配给eden区域。但随着时间的推移,旧的gen不再适合1.5G,堆的大小也随之改变。这似乎是无害的。但问题似乎在于调整规模的方式

所有4G现在都分配给了老世代地区,几乎没有一个分配给伊甸园地区。现在,当需要将某些内容分配给eden时,堆会再次调整大小。这成为了新的常态,堆被反复调整大小,导致应用程序的巨大性能成本

在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日志

似乎有以下两种gc原因:

  • [GC暂停(G1巨大分配)(年轻)(初始标记)
  • [GC暂停(G1疏散暂停)(年轻)(至空间耗尽)
庞大的资源分配需要老一代的空间,而空间的耗竭会推高年轻一代的规模。它们基本上是在相互竞争

看起来您正在分配大量庞大的对象(>1/2 G1区域大小),比IHOP启动的并发循环收集它们的速度还要快


您可以尝试增加区域大小。如果它们是大型基本体数组(即,非引用arrasy)那么实验可能也会有所帮助。

请您分享您在应用程序启动期间设置的所有参数好吗?@SauliusNext我现在已经在问题中添加了参数列表。对于G1GC,唯一的区别是添加了-XX:+useg1gc,因为您已经启用了GC日志,您应该从peri中附加足够长的GC日志感兴趣的od。@SasidharSekar我代表您提交了一个问题。请检查Oracle“Thomas Schatzl”高级GC工程师提供的建议,如果您需要进一步的澄清,请务必告诉我。感谢@Fairoz澄清了许多问题。我将尝试这些建议,看看情况如何改善。是的。我的应用程序实际上分配了很多庞大的对象。不幸的是,您所指的急切回收功能似乎仅适用于OpenJDK(我正在使用Hotspot JVM)但是,在阅读了您和@sauliusNext提到的评论之后,我想我将尝试以下选项,看看这有什么帮助。-XX:maxgcpausemilis-XX:g1mixedclievethresholdpercent=-XX:g1mixedccounttarget=-XX:G1OldCSetRegionThresholdPercent=在整个练习结束时,我意识到您关于增加se区域大小解决了我的问题。谢谢:-)