AW: ParallelGC issue: collector does only Full GC by default and above NewSize=1800m
Andreas Müller
Andreas.Mueller at mgm-tp.com
Fri Oct 25 01:29:15 PDT 2013
Hi Tao,
start the sample with ParNewGC and the same additional parameters as for ParallelGC:
java -Xms6g -Xmx6g -XX:NewSize=%1m -XX:MaxNewSize=%1m -XX:+UseParNewGC -Xloggc:gc_parnew_6g_New%1m.log -XX:+PrintGCDetails -cp GCBench.jar de.am.gc.benchmarks.MixedRandomList 100 8 12500000 (so %1 is the script parameter controlling the new size)
I have attached you the (shortened) gc.log for NewSize=MaxNewSize=2500m.
Note that the absolute throughput with ParNewGC is in fact a bit (5%) lower than shown in my previous graph.
Your question made me check the start script and I found that by error the ParNew script ran the sample with 20% less live heap than the other collectors (last parameter was 10000000 instead of 12500000. This made ParNew look even better than it actually is.
Anyway, as you can see from the sample log it does not have ParallelGC's problem above NewSize=1800m.
Regards
Andreas
Von: Tao Mao [mailto:tao.mao at oracle.com]
Gesendet: Freitag, 25. Oktober 2013 02:23
An: Andreas Müller
Cc: 'hotspot-gc-use at openjdk.java.net' (hotspot-gc-use at openjdk.java.net)
Betreff: Re: ParallelGC issue: collector does only Full GC by default and above NewSize=1800m
Hi Andreas,
What's your exact VM options for ParNewGC? If possible, please attach ParNew gc log. I'd like to investigate and compare the two cases to see GC behavioral differences.
Thanks.
Tao
On 10/21/13 10:09 AM, Andreas Müller wrote:
Hi all,
while experimenting a bit with different Garbage Collectors and applying them to my homegrown micro benchmarks I stumbled into the
following problem:
I run the below sample with the following command line (using Java 1.7.0_40 on Windows and probably others):
java -Xms6g -Xmx6g -XX:+UseParallelGC - de.am.gc.benchmarks.MixedRandomList 100 8 12500000
The Default and proven ParallelGC collector does mostly Full GCs and shows only poor out-of-the-box performance, more than a factor 10 lower than the ParNew collector.
More tests adding the -XX:NewSize=<xyz>m and -XX:MaxNewSize=<xyz>m reveal that the problem occurs as soon as the NewSize rises beyond 1800m which it obviously does by default.
Below that threshold ParallelGC performance is similar to ParNewGC (in the range of 7500 MB/s on my i7-2500MHz notebook), but at NewSize=2000m is as low as 600 MB/s.
Any ideas why this might happen?
Note that the sample is constructed such that the live heap is always around 3GB. If any I would expect a problem only at around NewSize=3GB, when Old Gen shrinks to less than the live heap size. As a matter of fact, ParNewGC can do >7000 MB/s from NewSize=400m to NewSize=3500m with little variation around a maximum of 7600 MB/s at NewSize=2000m.
I also provide source, gc.log and a plot of the NewSize dependency to anyone interested in that problem.
Regards
Andreas
-------------------------------------------------------MixedRandomList.java------------------------------------------------------------------------------------------------------------------------
package de.am.gc.benchmarks;
import java.util.ArrayList;
import java.util.List;
/**
* GC benchmark producing a mix of lifetime=0 and lifetime>0 objects which are kept in randomly updated lists.
*
* @author Andreas Mueller
*/
public class MixedRandomList {
private static final int DEFAULT_NUMBEROFTHREADS=1;
// object size in bytes
private static final int DEFAULT_OBJECTSIZE=100;
private static int numberOfThreads=DEFAULT_NUMBEROFTHREADS;
private static int objectSize=DEFAULT_OBJECTSIZE;
// number of objects to fill half of the available memory with (permanent) live objects
private static long numLive = (Runtime.getRuntime().maxMemory()/objectSize/5);
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
if( args.length>0 ) {
// first, optional argument is the size of the objects
objectSize = Integer.parseInt(args[0]);
// second, optional argument is the number of live objects
if( args.length>1 ) {
numberOfThreads = Integer.parseInt(args[1]);
// third, optional argument is the number of live objects
if( args.length>2 ) {
numLive = Long.parseLong(args[2]);
}
}
}
for( int i=0; i<numberOfThreads; i++ ) {
// run several GarbageProducer threads, each with its own mix of lifetime=0 and higher lifetime objects
new Thread(new GarbageProducer((int)Math.pow(50.0,(double)(i+1)), numLive/numberOfThreads)).start();
}
try {
Thread.sleep(1200000);
} catch( InterruptedException iexc) {
iexc.printStackTrace();
}
System.exit(0);
}
private static char[] getCharArray(int length) {
char[] retVal = new char[length];
for(int i=0; i<length; i++ ) {
retVal[i] = 'a';
}
return retVal;
}
public static class GarbageProducer implements Runnable {
// the fraction of newly created objects that do not become garbage immediately but are stored in the liveList
int fractionLive;
// the size of the liveList
long myNumLive;
/**
* Each GarbageProducer creates objects that become garbage immediately (lifetime=0) and
* objects that become garbage only after a lifetime>0 which is distributed about an average lifetime.
* This average lifetime is a function of fractionLive and numLive
*
* @param fractionLive
* @param numLive
*/
public GarbageProducer(int fractionLive, long numLive) {
this.fractionLive = fractionLive;
this.myNumLive = numLive;
}
@Override
public void run() {
int osize = objectSize;
char[] chars = getCharArray(objectSize);
List<String> liveList = new ArrayList<String>((int)myNumLive);
// initially, the lifeList is filled
for(int i=0; i<myNumLive; i++) {
liveList.add(new String(chars));
}
while(true) {
// create the majority of objects as garbage
for(int i=0; i<fractionLive; i++) {
String garbageObject = new String(chars);
}
// keep the fraction of objects live by placing them in the list (at a random index)
int index = (int)(Math.random()*myNumLive);
liveList.set(index, new String(chars));
}
}
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Andreas Müller
mgm technology partners GmbH
Frankfurter Ring 105a
80807 München
Tel. +49 (89) 35 86 80-633
Fax +49 (89) 35 86 80-288
E-Mail Andreas.Mueller at mgm-tp.com<mailto:Andreas.Mueller at mgm-tp.com>
Innovation Implemented.
Sitz der Gesellschaft: München
Geschäftsführer: Hamarz Mehmanesh
Handelsregister: AG München HRB 105068
_______________________________________________
hotspot-gc-use mailing list
hotspot-gc-use at openjdk.java.net<mailto:hotspot-gc-use at openjdk.java.net>
http://mail.openjdk.java.net/mailman/listinfo/hotspot-gc-use
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-gc-use/attachments/20131025/124f53d8/attachment-0001.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: gc_parnew_6g_New2500m.7z
Type: application/octet-stream
Size: 26899 bytes
Desc: gc_parnew_6g_New2500m.7z
Url : http://mail.openjdk.java.net/pipermail/hotspot-gc-use/attachments/20131025/124f53d8/gc_parnew_6g_New2500m-0001.7z
More information about the hotspot-gc-use
mailing list