增加次要GC暂停时间

时间:2015-09-16 10:31:00

标签: java garbage-collection jvm

我们正面临一个与次要GC有关的奇怪问题。我们的应用程序自去年18个月开始投入生产,最近开始有较高的次要gc暂停时间。从历史上看,我们的次要GC暂停时间约为30-50毫秒,但现在它们大约为110毫秒到400毫秒。堆配置没有任何变化,但代码更改的数量已经很多。

该应用程序是一个在tomcat上运行的Rest Web服务,托管在具有8个cpu虚拟机和24 GB RAM的云上,并与cassandra交谈。我们尝试通过运行性能测试来重新创建在较低环境中调试相同问题但不能这样做的问题。有一个单独的休息服务,使用类似的工作负载调用98%的时间,但2%的工作负载有点不同。由于数据问题,我们无法加载测试这2%的呼叫。

当我们运行负载时,我们看到几乎相同数量的堆被回收或提升,就像在正常情况下一样(当我们运行负载测试时,负载是生产的8-10倍)但是较小的gc暂停总是<50毫秒。 (我们确实在生产VM上运行与读取操作相同的负载)

使用性能测试请求(高负载):

2015-09-15T10:16:51.617+0000: 300001.062: [GC (Allocation Failure) [PSYoungGen: 1922537K->174564K(1922560K)] 2146305K->432640K(4019712K), 0.0604696 secs] [Times: user=0.44 sys=0.00, real=0.06 secs]
2015-09-15T10:16:54.033+0000: 300003.478: [GC (Allocation Failure) [PSYoungGen: 1922383K->174567K(1922560K)] 2180459K->469257K(4019712K), 0.0493751 secs] [Times: user=0.28 sys=0.00, real=0.05 secs]
2015-09-15T10:16:56.468+0000: 300005.912: [GC (Allocation Failure) [PSYoungGen: 1922535K->174570K(1922560K)] 2217225K->504099K(4019712K), 0.0437478 secs] [Times: user=0.27 sys=0.00, real=0.05 secs]
2015-09-15T10:16:58.696+0000: 300008.140: [GC (Allocation Failure) [PSYoungGen: 1922538K->174576K(1922560K)] 2252067K->541818K(4019712K), 0.0407501 secs] [Times: user=0.25 sys=0.00, real=0.04 secs]
2015-09-15T10:17:00.887+0000: 300010.331: [GC (Allocation Failure) [PSYoungGen: 1922544K->174573K(1922560K)] 2289786K->577682K(4019712K), 0.0468752 secs] [Times: user=0.32 sys=0.00, real=0.05 secs]
2015-09-15T10:17:03.142+0000: 300012.586: [GC (Allocation Failure) [PSYoungGen: 1922541K->174581K(1922560K)] 2325650K->617970K(4019712K), 0.0424797 secs] [Times: user=0.26 sys=0.00, real=0.04 secs]
2015-09-15T10:17:05.394+0000: 300014.838: [GC (Allocation Failure) [PSYoungGen: 1922549K->174587K(1922560K)] 2365938K->659487K(4019712K), 0.0425134 secs] [Times: user=0.27 sys=0.00, real=0.04 secs]
2015-09-15T10:17:07.661+0000: 300017.106: [GC (Allocation Failure) [PSYoungGen: 1922555K->174566K(1922560K)] 2407455K->694256K(4019712K), 0.0389039 secs] [Times: user=0.24 sys=0.00, real=0.04 secs]
2015-09-15T10:17:09.951+0000: 300019.395: [GC (Allocation Failure) [PSYoungGen: 1922534K->174577K(1922560K)] 2442224K->726822K(4019712K), 0.0385114 secs] [Times: user=0.29 sys=0.00, real=0.03 secs]
2015-09-15T10:17:12.302+0000: 300021.746: [GC (Allocation Failure) [PSYoungGen: 1922545K->174591K(1922560K)] 2474790K->762111K(4019712K), 0.0400951 secs] [Times: user=0.28 sys=0.00, real=0.04 secs]

但是在同一台机器上同一JVM的生产负载要小得多,次要的GC暂停非常高:

015-09-15T05:36:27.428+0000: 283176.872: [GC (Allocation Failure) [PSYoungGen: 1844205K->125665K(1922560K)] 1991878K->273338K(4019712K), 0.1087286 secs] [Times: user=0.61 sys=0.00, real=0.11 secs]
2015-09-15T05:39:05.945+0000: 283335.390: [GC (Allocation Failure) [PSYoungGen: 1873633K->157526K(1922560K)] 2021306K->305200K(4019712K), 0.1099762 secs] [Times: user=0.58 sys=0.00, real=0.11 secs]
2015-09-15T05:41:43.686+0000: 283493.131: [GC (Allocation Failure) [PSYoungGen: 1905494K->174576K(1922560K)] 2053168K->337666K(4019712K), 0.1249486 secs] [Times: user=0.70 sys=0.00, real=0.13 secs]
2015-09-15T05:45:06.059+0000: 283695.503: [GC (Allocation Failure) [PSYoungGen: 1922544K->174560K(1922560K)] 2085634K->371522K(4019712K), 0.1434632 secs] [Times: user=0.95 sys=0.00, real=0.15 secs]
2015-09-15T05:48:08.511+0000: 283877.955: [GC (Allocation Failure) [PSYoungGen: 1922528K->174576K(1922560K)] 2119490K->404319K(4019712K), 0.1145014 secs] [Times: user=0.76 sys=0.00, real=0.11 secs]
2015-09-15T05:50:49.150+0000: 284038.594: [GC (Allocation Failure) [PSYoungGen: 1922544K->174571K(1922560K)] 2152287K->436331K(4019712K), 0.1178926 secs] [Times: user=0.68 sys=0.00, real=0.12 secs]
2015-09-15T05:54:18.962+0000: 284248.407: [GC (Allocation Failure) [PSYoungGen: 1922539K->174560K(1922560K)] 2184299K->467992K(4019712K), 0.0975615 secs] [Times: user=0.63 sys=0.00, real=0.10 secs]
2015-09-15T05:57:45.177+0000: 284454.621: [GC (Allocation Failure) [PSYoungGen: 1922240K->174577K(1922560K)] 2215672K->501369K(4019712K), 0.1108669 secs] [Times: user=0.75 sys=0.00, real=0.11 secs]
2015-09-15T06:00:55.609+0000: 284645.053: [GC (Allocation Failure) [PSYoungGen: 1922545K->174584K(1922560K)] 2249337K->534084K(4019712K), 0.0970370 secs] [Times: user=0.65 sys=0.00, real=0.10 secs]
2015-09-15T06:03:32.692+0000: 284802.137: [GC (Allocation Failure) [PSYoungGen: 1922552K->174582K(1922560K)] 2282052K->569585K(4019712K), 0.1109909 secs] [Times: user=0.80 sys=0.00, real=0.11 secs]
2015-09-15T06:06:14.975+0000: 284964.420: [GC (Allocation Failure) [PSYoungGen: 1922550K->174586K(1922560K)] 2317553K->599629K(4019712K), 0.0967938 secs] [Times: user=0.41 sys=0.00, real=0.10 secs]

现在,如果次要GC暂停时间包括卡片扫描,堆栈扫描,旧生成扫描和复制时间,如果在上述情况下不相同,那么所有这些都应该是相似的,那么GC暂停时间是如此不同?或者我在这里缺少一些非常基本的东西?

JVM Version Info:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

堆参数是:

-XX:+DisableExplicitGC
-XX:GCLogFileSize=10485760
-XX:+HeapDumpOnOutOfMemoryError
-XX:InitialHeapSize=4G
-XX:MaxHeapSize=4G
-Xmn2G
-XX:NumberOfGCLogFiles=25
-XX:+PrintGC -XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution
-XX:SurvivorRatio=10 -XX:-UseAdaptiveSizePolicy
-XX:+UseCompressedOops -XX:+UseGCLogFileRotation
-XX:+UseParallelGC -XX:+UseParallelOldGC

1 个答案:

答案 0 :(得分:0)

您正在使用具有throughput as its primary goal的并行收集器。因此,在不同的工作负载下实现吞吐量目标可能会有不同的权衡,这并不奇怪。

如果希望它保持低位暂停,则必须指定pause time goal.

官方文件中明确说明了这一点:

  

默认情况下,没有最大暂停时间目标。

因此,我发现您尝试了所有这些GC参数但却没有尝试前几段中提供的那些参数,这让我感到惊讶。

如果你是cargo-culting来自其他地方的参数,我强烈建议你不要在没有先参考文档来理解它们的目的的情况下这样做。

编辑:仔细查看您正在使用的选项,您可以固定生存者比率并禁用自适应大小政策,从而阻止GC调整新的gen以满足暂停时间目标。< / p>

在不同的工作负载(测试与生产)下,对象的年龄分布会有所不同,因此需要从托儿所和空间中标记和复制活动对象的数量。

这会导致不同的暂停时间。

相反,您可能应该只指定高级目标,并让启发式方法适应不断变化的工作负载。

相关问题