3
votes

I'm experimenting a little with the parallel GC, basically I'm trying to set the survivor space size to the maximum observed on previous runs to avoid survivor space overflow. In my case a survivor size of 96mX2 should be fine. To avoid survivor space resizing by the jvm I turn off the AdaptiveSizePolicy.

Obviously I'm missing something because I'm getting constant overflows with very little load on the application, but still is a strange overflow as the old generation space seems to not increase as it should when overflowing.

These are the jvm args on a Java 1.7.0_51 jvm:

java -D[Standalone] -server -XX:+UseCompressedOops -Xms3328m -Xmx3328m -Xmn1152m -XX:SurvivorRatio=10 -XX:PermSize=132m -XX:MaxPermSize=132m -XX:+UseParallelOldGC -XX:-UseAdaptiveSizePolicy -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:/usr/local/java/jboss/standalone/log/gc.log

And these are the garbage collection logs

2014-02-10T09:56:26.104+0200: 39544.174: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 100636800 promoted: 10963760 overflow: true [PSYoungGen: 1081318K->98278K(1081344K)] 1869646K->897313K(3309568K), 0.1578000 secs] [Times: user=0.57 sys=0.03, real=0.16 secs]

2014-02-10T10:02:24.729+0200: 39902.799: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 100648968 promoted: 19202536 overflow: true [PSYoungGen: 1081318K->98290K(1081344K)] 1880353K->916077K(3309568K), 0.1893170 secs] [Times: user=0.64 sys=0.09, real=0.19 secs]

Here the heap occupancy in old gen increased by 19m not by 96m (the size of survivor space). And so on the rest of the logs.

2014-02-10T10:05:17.796+0200: 40075.866: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 100623664 promoted: 1384448 overflow: false [PSYoungGen: 1081330K->98265K(1081344K)] 1899117K->917405K(3309568K), 0.1350010 secs] [Times: user=0.51 sys=0.01, real=0.13 secs]

2014-02-10T10:07:56.135+0200: 40234.204: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 100650360 promoted: 19069104 overflow: true [PSYoungGen: 1081305K->98291K(1081344K)] 1900445K->936053K(3309568K), 0.1847340 secs] [Times: user=0.64 sys=0.08, real=0.18 secs]

2014-02-10T10:08:26.613+0200: 40264.682: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 100658976 promoted: 12245304 overflow: true [PSYoungGen: 1081331K->98299K(1081344K)] 1919093K->948020K(3309568K), 0.1578130 secs] [Times: user=0.57 sys=0.04, real=0.16 secs]

So the question is: what I'm missing? Why so many objects seem to survive? With the AdaptiveSizePolicy turned on, the survival rate is really low on the same load.

1

1 Answers

1
votes

After some more experimentation I think I've found the answer.

First of all the parallel GC overflows to old generation only what's above the survivor space, not the entire survivor space as I wrongly stated in the question.

Secondly, when disabling the AdaptiveSizePolicy the tenuring threshold defaults to 2 or more, a value larger than 1 (the value calculated in 99% of the cases by the AdaptiveSizePolicy when almost no overflow occured). So, on every minor collection the GC tries to copy what's living in the first survivor space to the second one, but here is not enough space (there are also living objects from eden that need to fit) so it overflows to old generation.

Setting the initial tenuring threshold and max tenuring threshold to 1 prevented constant overflow while keeping the survivor spaces large enough as I originaly intended:

java -D[Standalone] -server -XX:+UseCompressedOops -Xms3328m -Xmx3328m -Xmn1152m -XX:SurvivorRatio=10 -XX:PermSize=132m -XX:MaxPermSize=132m -XX:+UseParallelOldGC -XX:-UseAdaptiveSizePolicy -XX:InitialTenuringThreshold=1 -XX:MaxTenuringThreshold=1 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:/usr/local/java/jboss/standalone/log/gc.log

Here is a log printed by the AdaptiveSizePolicy when turned on:

2014-02-12T20:31:28.967+0200: 74464.855: [GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh: survived: 21423336 promoted: 4189088 overflow: false

AdaptiveSizeStart: 74464.928 collection: 250
avg_survived_padded_avg: 35720128.000000 avg_promoted_padded_avg: 21338244.000000 avg_pretenured_padded_avg: 0.000000 tenuring_thresh: 1 target_size: 36175872PS ...

Interestingly, this aging of 1 makes quite a difference in application performance compared with the constant overflow to old generation, mostly in less minor collection time but also a smaller Full GC frequency.