2017-02-14 107 views
2

我有一个在tomcat上运行的web应用程序,它的最大堆大小设置为8GB。什么导致完整的GC运行?

以下是我的vm参数。

export CATALINA_OPTS="$CATALINA_OPTS -Xms512m -Xmx8192m -XX:+UseConcMarkSweepGC" 

如果没有用户登录到应用程序,那么不可清除的内存(位于垃圾收集之后)非常低(约1GB)。

在这种情况下,如果我观察使用jconsole内存的增长模式,我看到约4GB恒定的内存增长,然后垃圾收集器运行和内存再次下降至约1 GB。这种模式继续下去,如果没有用户获取登录。

如果我登录了GC数据,我看到类似下面。

2017-02-14T15:30:44.553+0530: 591.922: [GC (Allocation Failure) [PSYoungGen: 1501051K->631966K(1833472K)] 2392189K->1523112K(3030016K), 1.5100144 secs] [Times: user=1.49 sys=0.01, real=1.51 secs] 
2017-02-14T15:31:20.335+0530: 627.705: [GC (Allocation Failure) [PSYoungGen: 1553054K->595007K(1842176K)] 2444200K->1570521K(3038720K), 1.3050284 secs] [Times: user=1.27 sys=0.04, real=1.31 secs] 
2017-02-14T15:33:33.682+0530: 761.052: [GC (Allocation Failure) [PSYoungGen: 1516095K->556800K(1842176K)] 2491609K->1596474K(3038720K), 1.6957154 secs] [Times: user=1.67 sys=0.03, real=1.69 secs] 
2017-02-14T15:33:35.378+0530: 762.748: [Full GC (Ergonomics) [PSYoungGen: 556800K->365446K(1842176K)] [ParOldGen: 1039673K->1196476K(2018304K)] 1596474K->1561923K(3860480K), [Metaspace: 70472K->70472K(1114112K)], 11.2779843 secs] [Times: user=11.13 sys=0.09, real=11.28 secs] 
2017-02-14T15:34:56.232+0530: 843.602: [GC (Allocation Failure) [PSYoungGen: 1286534K->216613K(1842176K)] 2483011K->1609875K(3860480K), 1.4938761 secs] [Times: user=1.45 sys=0.05, real=1.50 secs] 

如可以看到的那样,有时一个完整GC进行,相比于较小的GC已经采取了相当长的时间(11秒),(〜1秒)。

因为所有其他线程被GC期间暂停,如果用户尝试一个完整的GC期间访问Web应用程序,服务器没有响应。

我想知道的是什么触发了这个完整的GC?根据日志,小gc事件是由于分配失败造成的,Full GC由于Ergonomics而导致。这是什么意思?

有没有什么办法可以防止满GC在这种情况下发生?还有很多可用的堆空间,我想延迟Full GC发生,直到由于较小的GC而没有显着的内存减少。

+1

能否请您添加要使用(XMS,MaxGCPauseMillis,其集热器,...),加上您的服务器的物理内存的所有GC-VM相关的选项。如果你想暂停时间很短,那么延迟完整的gcs并不是一种可行的方式,因为暂停会更少但更长。所以在我看来,你的堆配置得太大了,无法实现你想要实现的目标(再加上你使用了错误的collection-algorithm)。 –

+0

@ piet.t,添加到问题的虚拟机选项 –

+0

应用程序可能在代码中某处显式调用'System.gc()'调用。我看到CMS收集器有点疯狂,并且在调用System.gc()后总是执行停止全局GC。您可以通过'-XX:+ DisableExplicitGC' JVM选项使GC忽略此类调用。 –

回答

0

解决您的首要问题(服务器档口花了垃圾收集,由于过多的时间),这可能是用于一些原因是由于错误的垃圾收集器。垃圾收集调整记录在here。通过Garbage-First collector,您可以设置任何可以接受的暂停(默认值为200毫秒,这对服务器来说应该不是什么大问题)。

0

我想指出你的Parallel Collector链接。 “人体工程学”是一种利用应用程序的特定行为自动调节收集器的方法。

大多数情况下,自动调整是好的。在你的情况下,它似乎是以太长的GC结束。您可以通过调整收集器的参数来修复它。

引用文档:

最大垃圾回收暂停时间

最大停顿时间目标与命令行选项-XX规定:MaxGCPauseMillis =。这被解释为希望暂停时间为毫秒或更短的提示;默认情况下,没有最大暂停时间目标。如果指定了暂停时间目标,则会调整与垃圾收集相关的堆大小和其他参数,以尝试使垃圾收集暂停时间短于指定值。这些调整可能会导致垃圾收集器降低应用程序的整体吞吐量,并且不能始终满足所需的暂停时间目标。

吞吐量

吞吐量的目标中的时间来测量执行垃圾回收与垃圾收集的外花的时间(被称为应用时间)。目标由命令行选项-XX:GCTimeRatio =指定,该选项将垃圾收集时间与应用程序时间的比率设置为1 /(1 +)。

例如,-XX:GCTimeRatio = 19设置垃圾收集总时间的1/20或5%的目标。默认值为99,导致垃圾收集时间的目标为1%。

足迹

最大堆足迹使用选项-Xmx指定。另外,只要其他目标得到满足,收集器就有一个隐含的目标,即尽可能减小堆的大小。

+0

-XX:MaxGCPauseMillis对我来说看起来是一个不错的选择,但它能够最小化完整GC所需的时间吗?在我的情况下,小GC运行速度非常快,但全GC大约需要10倍。我怀疑-XX:MaxGCPauseMillis是否可以把这个降到1秒左右。 –

+0

@LahiruChandima当然不,当然,它会尽量尊重设定的时间,但这只是一个提示。如果在定制GC之后仍然存在问题,则应该调查为什么有太多垃圾对象以及为什么不能在更小的时间范围内完成。 –

+0

我将添加-XX:MaxGCPauseMillis并检查。实际上我并不认为整个GC的持续时间较长是由于大量的对象数。正如我通过jconsole所观察到的那样,当小GC发生时,它会在不到2秒的时间内移除大约3GB的垃圾对象。 –

相关问题