Tenured collection starting for no apparent reason

2019-06-13 17:08发布

问题:

I have a Java application that normally has very healthy garbage collection statistics. A tenured collection normally happens every hour or so and the STW portions take just fractions of a second. But strangely a collection always happens within about the first five minutes of app startup. This is a real problem because at that time, CPU usage is already much higher than normal (due to increased network calls that eventually get cached), so these pauses are always longer than normal and even run past 8 seconds if I'm doing a restart under extremely heavy load.

Here are the JVM args:

-Xms4096m 
-Xmx4096m 
-XX:PermSize=768m 
-XX:MaxPermSize=768m 
-XX:SurvivorRatio=6 
-XX:NewSize=1024m 
-verbose:gc 
-XX:-DisableExplicitGC 
-XX:+PrintGCDetails 
-XX:+PrintGCApplicationStoppedTime 
-XX:+PrintGCTimeStamps 
-XX:+PrintHeapAtGC 
-XX:+PrintTenuringDistribution 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:MaxDirectMemorySize=2048m 
-XX:+UseConcMarkSweepGC 
-XX:+CMSClassUnloadingEnabled 
-XX:+PrintConcurrentLocks 
-XX:+ExplicitGCInvokesConcurrent 

The question here is what triggers this tenured collection since there is almost 2gb free in old gen when it occurs. Here's the usage under normal circumstances right before a tenured collection:

concurrent mark-sweep generation total 3145728K, used 2897098K 

And here's the usage just before a tenured collection is triggered within the first few minutes of startup:

concurrent mark-sweep generation total 3145728K, used 1573655K 

My understanding is that a tenured collection should only occur when old gen is nearly full; what could trigger it otherwise?

回答1:

A key concept of the CMS is that it should start collecting before you run out of space, thus allowing it to run concurrently. If it waited until you ran out it would trigger a serial stop the world collection.

For this reason there is two thresholds to determine when to trigger a collection prematurely.

-XX:CMSInitiatingOccupancyFraction=90 (by default)
-XX+UseCMSInitiatingOccupancyOnly

If you don't set these, it will work out when it a good time to start using "metrics"

My understanding is that a tenured collection should only occur when old gen is nearly full;

This is what the Parallel Collector does.