08 August 2013

A Java program that triggers the java.lang.OutOfMemoryError: GC overhead limit exceeded

I wanted to test how the -XX:+HeapDumpOnOutOfMemoryError JVM option worked when a JVM goes out of memory, but because of GC overheadlimit. This is my try:

import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;


public class OutOfMemoryProvoker {
    
    private static final int MEMORY_BLOCK_MAX_SIZE = 1000000;
    private static final int REMOVE_BLOCK_FACTOR = 20000;

    public static void main(String[] args) throws Exception {
        final ArrayList<byte[]> list = new ArrayList<byte[]>();
        
        Random random = new Random(0);
        
        Timer timer = new Timer("reportTimer");
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                report(list);
            }
        }, 5000, 5000);
        
        while (true) {
            int memSize = random.nextInt(MEMORY_BLOCK_MAX_SIZE) + 1;
            
            byte[] memBlock = new byte[memSize];
            list.add(memBlock);
            
            
            int removeBlockIndex = random.nextInt(REMOVE_BLOCK_FACTOR);
            if (list.size() > removeBlockIndex) {
                list.remove(removeBlockIndex);
            }
        }
    }

    private static void report(ArrayList<byte[]> list) {
        System.out.println(list.size());
    }
}

This works very nice. You have to modify the MEMORY_BLOCK_MAX_SIZE and REMOVE_BLOCK_FACTOR to match your memory settings. I used a 8 GB heap for my numbers.

Nice things to note:
  1. Java GC really dislikes different sizes of memory block. This is why I randomize the memory block sizes to provoke as much GC work as possible
  2. The REMOVE_BLOCK_FACTOR controls the chance that a memory block is dereferenced and eligible for GC. It simply removes an item from the list (if the list is big enough). This has the nice characteristic the the chance that a block is removed is higher the more the list is filled.