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.
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 threadExample 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 memoryExample 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 exceededTesting 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
