How do I stress the JVM's GC?

Viewed 238

How do I drive the garbage collection activity to some significant level, say, 10% or more, preferrably without running into an out-of-memory condition?

I have been trying to build code that does this, but I'm not getting anywhere near 10%.

What approaches are there? I tried a pool of randomly-sized blocks which are being replaced in random order, with newly created randomly-sized-again blocks; this is giving me ca. 20% CPU and 0.6%GC in VisualVM, slightly varying with pool and block sizes.

4 Answers

You might want to take a look here to get few ideas. Basically the technique used in above example is to create fragmentation of Java heap memory as objects are added and removed from the LinkedHashMap being used as a cache. Running on my local with 300m max memory to JVM (java -Xmx300m -jar gcstress.jar) I was able to generate 20% consistent CPU usage for garbage collection.

enter image description here

One way to cause the GC to spend a lot of time is to almost fill up the heap and then trigger repeated garbage collections by allocating and discarding1 lots of temporary objects.

A typical generational GC spends most of its time tracing and moving non-garbage objects from one space to another. When the heap is nearly full of non-garbage objects, and you trigger the GC repeatedly, it does a lot of work for very little gain (in terms of space reclaimed).

Another way (assuming that explicit GC has not been disabled) is to repeatedly call System.gc().


1 - That is, not keeping a reference to the object so that it is almost immediately unreachable.

You can do a humongous allocation (assuming G1GC with defaults):

public class Del {

    public static void main(String[] args) {
        for(int i=0;i<100_000;++i) {
            System.out.println(allocate());
        }
    }

    private static int allocate() {
        int [] x = ThreadLocalRandom.current().ints(1024 * 1024, 10, 10_000_000).toArray();
        return Arrays.hashCode(x);
    }

}

You can constrain the heap and also enable GC logs to see how bad is G1 trying to cope with the constant allocations:

java -Xmx100m -Xms100m "-Xlog:gc*=info" Del.java

Running this on my machine shows that the CPU is occupied, constantly, from that java process, because of constant GC activity.

[ONLY for debugging] Reduce the -XX:NewSize JVM parameter to a smaller size to trigger GC. This is for older GCs.

You can call System.gc() in program. Read here: Why it is bad to call System.gc()

Related