6 Common Java OOM Scenarios and How to Prevent Them

This article explores six typical OutOfMemoryError situations in Java—including heap, stack, direct memory, GC overhead, and metaspace issues—explains their root causes, provides reproducible code examples, and offers practical tips to avoid or mitigate each problem.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
6 Common Java OOM Scenarios and How to Prevent Them

Introduction

The author references previous articles on CPU spikes and API abuse, then introduces six common OOM (OutOfMemoryError) scenarios that can occur in online services.

1. Heap Memory OOM

Heap OOM is the most frequent type, triggered when the JVM heap cannot satisfy allocation requests. java.lang.OutOfMemoryError: Java heap space Example code creates an ever‑growing list in an infinite loop, quickly exhausting the heap.

public class HeapOOMTest {
    public static void main(String[] args) {
        List<HeapOOMTest> list = Lists.newArrayList();
        while (true) {
            list.add(new HeapOOMTest());
        }
    }
}

Typical causes include exporting massive Excel data or loading huge query results at once.

2. Stack Memory OOM (Thread Creation)

Creating too many threads can exhaust native stack memory, leading to OOM.

java.lang.OutOfMemoryError: unable to create new native thread

Example continuously spawns new threads in a loop.

public class StackOOMTest {
    public static void main(String[] args) {
        while (true) {
            new Thread().start();
        }
    }
}
Use thread pools instead of creating raw threads to avoid this OOM.

3. Stack Overflow (Recursion)

Deep or infinite recursion can overflow the JVM stack, producing a StackOverflowError. java.lang.StackOverflowError Example method calls itself without a termination condition.

public class StackFlowTest {
    public static void main(String[] args) {
        doSamething();
    }
    private static void doSamething() {
        doSamething();
    }
}
When writing recursive code, always limit recursion depth or add safeguards to prevent infinite loops.

4. Direct Memory OOM

Direct (off‑heap) memory, allocated via NIO's DirectByteBuffer, is not part of the JVM heap and can run out when large buffers are repeatedly allocated.

java.lang.OutOfMemoryError: Direct buffer memory

Example continuously allocates 20 MB direct buffers.

public class DirectOOMTest {
    private static final int BUFFER = 1024 * 1024 * 20;
    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList<>();
        int count = 0;
        try {
            while (true) {
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                count++;
                Thread.sleep(100);
            }
        } finally {
            System.out.println(count);
        }
    }
}

The program eventually throws the Direct buffer memory OOM error.

5. GC Overhead OOM

When the garbage collector spends excessive time reclaiming memory (often due to too many objects), the JVM throws a GC overhead limit exceeded error.

java.lang.OutOfMemoryError: GC overhead limit exceeded

Testing with both -Xmx and -Xms set to 10 MB reproduces the issue. -Xmx10m -Xms10m Example creates an unbounded number of tasks in a fixed thread pool, causing continuous allocation.

public class GCOverheadOOM {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executor.execute(() -> {
                try { Thread.sleep(10000); } catch (InterruptedException e) {}
            });
        }
    }
}

Adjusting GC thresholds and survivor/new generation ratios can mitigate the problem.

6. Metaspace OOM

Since JDK 8, class metadata is stored in native Metaspace; exhausting it yields a Metaspace OOM. java.lang.OutOfMemoryError: Metaspace Setting both MetaspaceSize and MaxMetaspaceSize to 10 MB forces the error. -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m Example repeatedly generates dynamic proxy classes, quickly filling Metaspace.

public class MetaspaceOOMTest {
    static class OOM {}
    public static void main(String[] args) {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOM.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

The program finally throws java.lang.OutOfMemoryError: Metaspace, typically caused by loading too many or too large classes.

Conclusion

The article wraps up the six OOM cases and promises a next post on tools for locating OOM problems.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMperformanceMemory ManagementOutOfMemoryError
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.