Fundamentals 20 min read

Common Java OutOfMemoryError Types and Their Solutions

This article explains the various OutOfMemoryError variants in the Java Virtual Machine, illustrates each with reproducible code examples, analyzes root causes, and provides practical mitigation strategies such as JVM flags, code refactoring, and system‑level adjustments.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Common Java OutOfMemoryError Types and Their Solutions

1. StackOverflowError

The JVM stack has a limited depth; recursive calls without a termination condition eventually exhaust the stack and throw java.lang.StackOverflowError.

1.1 Example

public class StackOverflowErrorDemo {
    public static void main(String[] args) {
        javaKeeper();
    }
    private static void javaKeeper() {
        javaKeeper();
    }
}

Running this program produces:

Exception in thread "main" java.lang.StackOverflowError
    at oom.StackOverflowErrorDemo.javaKeeper(StackOverflowErrorDemo.java:15)

1.2 Causes

Infinite recursion (most common).

Executing a huge number of methods causing stack exhaustion.

Declaring massive local variables.

Native code that allocates large buffers on the stack (e.g., java.net.SocketInputStream.read0).

1.3 Solutions

Fix the recursive logic and remove infinite calls.

Check for circular class dependencies that may trigger recursion via toString().

Increase thread stack size with the JVM option -Xss when necessary.

2. Java Heap Space

The Java heap stores object instances. Continuously creating objects until the heap reaches its maximum size triggers java.lang.OutOfMemoryError: Java heap space, the most common OOM in real applications.

2.1 Example

/**
 * JVM parameter: -Xmx12m
 */
public class JavaHeapSpaceDemo {
    static final int SIZE = 2 * 1024 * 1024;
    public static void main(String[] a) {
        int[] i = new int[SIZE];
    }
}

Running with -Xmx12m results in:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at oom.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:13)

2.2 Causes

Attempting to allocate an excessively large object (e.g., a huge array).

Unexpected traffic spikes causing massive object creation.

Overuse of finalizers preventing timely GC.

Memory leaks where object references are never released (e.g., unclosed File resources).

2.3 Solutions

Usually increasing the heap size with -Xmx solves the problem. If the issue persists:

Validate the necessity of large objects; limit result set sizes.

Apply rate‑limiting or degrade service under high load.

Detect and fix memory leaks by releasing resources properly.

3. GC Overhead Limit Exceeded

When the JVM spends more than 98% of its time performing GC and recovers less than 2% of heap memory for five consecutive cycles, it throws java.lang.OutOfMemoryError: GC overhead limit exceeded, indicating the application has almost exhausted all usable memory.

3.1 Example

/**
 * JVM parameters: -Xmx14m -XX:+PrintGCDetails
 */
public class KeylessEntry {
    static class Key {
        Integer id;
        Key(Integer id) { this.id = id; }
        @Override public int hashCode() { return id.hashCode(); }
    }
    public static void main(String[] args) {
        Map m = new HashMap();
        while (true) {
            for (int i = 0; i < 1000; i++) {
                if (!m.containsKey(new Key(i))) {
                    m.put(new Key(i), "Number:" + i);
                }
            }
            System.out.println("m.size()=" + m.size());
        }
    }
}

Output shows the map growing beyond the intended limit and eventually:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

The problem stems from overriding hashCode() without overriding equals(), causing containsKey() to fail and the map to grow indefinitely.

3.2 Solutions

Disable the limit (not recommended) with -XX:-UseGCOverheadLimit.

Identify and eliminate infinite loops or memory‑intensive code.

Perform heap dumps and analyze for leaks before simply increasing memory.

4. Direct Buffer Memory

Using NIO's ByteBuffer.allocateDirect allocates off‑heap (native) memory. If native memory is exhausted, the JVM throws java.lang.OutOfMemoryError: Direct buffer memory.

4.1 Example

/**
 * VM Options: -Xms10m,-Xmx10m,-XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 */
public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
        System.out.println("maxDirectMemory is:" + sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB");
        //ByteBuffer buffer = ByteBuffer.allocate(6*1024*1024);
        ByteBuffer buffer = ByteBuffer.allocateDirect(6*1024*1024);
    }
}

Running with -XX:MaxDirectMemorySize=5m yields:

maxDirectMemory is:5MB
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

4.2 Solutions

Use ByteBuffer.allocateDirect sparingly; monitor with tools like Arthas.

Check for indirect NIO usage (Netty, Jetty, etc.).

Adjust the limit via -XX:MaxDirectMemorySize.

Remove -XX:+DisableExplicitGC if present, so System.gc() can reclaim direct buffers.

Manually clean buffers via sun.misc.Cleaner.clean() when appropriate.

Upgrade hardware if native memory truly runs out.

5. Unable to Create New Native Thread

Each Java thread maps to a native OS thread. When the OS cannot allocate the required native memory or thread count limit is reached, the JVM throws java.lang.OutOfMemoryError: unable to create new native thread .

5.1 Example

public static void main(String[] args) {
    while (true) {
        new Thread(() -> {
            try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) {}
        }).start();
    }
}

Result:

Error occurred during initialization of VM
java.lang.OutOfMemoryError: unable to create new native thread

5.2 Causes

Exceeding the OS‑level maximum thread count.

Reaching kernel.pid_max (requires reboot).

Insufficient native memory (e.g., 32‑bit address space limits).

5.3 Solutions

Reduce the number of threads; use thread pools.

Increase OS limits with ulimit -u or equivalent.

6. Metaspace

Since Java 8, the permanent generation (PermGen) was replaced by Metaspace, which resides in native memory. Exhausting Metaspace results in java.lang.OutOfMemoryError: Metaspace .

6.1 Example

/**
 * JVM Options: -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
 */
public class MetaspaceOOMDemo {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MetaspaceOOMDemo.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
                return methodProxy.invokeSuper(o, objects);
            });
            enhancer.create();
        }
    }
}

Result:

org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace

6.2 Solutions

Limit Metaspace size with -XX:MaxMetaspaceSize.

Set initial size via -XX:MetaspaceSize to trigger timely GC of class metadata.

Adjust free‑ratio parameters ( -XX:MinMetaspaceFreeRatio, -XX:MaxMetaspaceFreeRatio) to control reclamation frequency.

7. Requested Array Size Exceeds VM Limit

7.1 Example

public static void main(String[] args) {
    int[] arr = new int[Integer.MAX_VALUE];
}

Result:

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit

The JVM caps the maximum array length (approximately Integer.MAX_VALUE-2 ). Creating larger arrays requires redesigning the data structure.

8. Out of Swap Space

When the total memory requested by the JVM exceeds physical memory, the OS starts swapping. If swap space is also exhausted, the JVM throws java.lang.OutOfMemoryError: Out of swap space .

9. Kill Process or Sacrifice Child

Linux’s OOM Killer may terminate processes when the system runs out of memory. The JVM may surface this as Kill process or sacrifice child , which originates from the OS rather than the JVM.

9.1 Causes

Processes consuming excessive memory, causing the kernel to invoke the OOM Killer.

Over‑commit settings allowing allocation beyond physical limits.

9.2 Solutions

Upgrade server resources or isolate workloads.

Tune the OOM Killer parameters to protect critical processes.

References: "深入理解 Java 虚拟机 第 3 版", plumbr.io, Alibaba Cloud articles, and the StabilityGuide GitHub repository.

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.

JavaJVMMemory ManagementOutOfMemoryError
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

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.