import java.util.ArrayList; import java.util.List; /** * Deliberately allocates and retains heap in fixed-size chunks until it is * killed or finishes, printing progress as it goes. Used to demonstrate what * actually happens when a container's memory limit, the JVM's heap flags, * and real allocation pressure disagree with each other. See the post at * https://ankurm.com/jvm-flags-for-spring-boot-in-containers-jdk-25-27/ * and docs/output/05-oom-*.txt / 06-oom-*.txt for the captured runs. */ public class MemoryHog { public static void main(String[] args) throws Exception { int chunkMb = args.length > 0 ? Integer.parseInt(args[0]) : 16; int sleepMs = args.length > 1 ? Integer.parseInt(args[1]) : 150; List held = new ArrayList<>(); long totalMb = 0; System.out.println("MemoryHog starting: chunk=" + chunkMb + "MB sleep=" + sleepMs + "ms"); System.out.flush(); while (true) { byte[] chunk = new byte[chunkMb * 1024 * 1024]; for (int i = 0; i < chunk.length; i += 4096) { chunk[i] = 1; // touch each page so it is actually resident, not just reserved } held.add(chunk); totalMb += chunkMb; Runtime rt = Runtime.getRuntime(); System.out.printf("held=%dMB heapUsed=%dMB heapMax=%dMB freeHeap=%dMB%n", totalMb, (rt.totalMemory() - rt.freeMemory()) / (1024 * 1024), rt.maxMemory() / (1024 * 1024), rt.freeMemory() / (1024 * 1024)); System.out.flush(); Thread.sleep(sleepMs); } } }