Common Errors in Java
Exceptions describe problems in your program's logic. Errors describe something more serious: the JVM itself has run out of a resource it needs. The two you'll meet are StackOverflowError, when method calls nest too deeply, and OutOfMemoryError, when the heap is full. Both extend Error, not Exception, which is Java's way of saying "you usually can't recover from this; fix the cause".
Running Out of Stack and Heap
import java.util.ArrayList;
import java.util.List;
public class Errors {
static int depth = 0;
static void dive() {
depth++;
dive();
}
public static void main(String[] args) {
try {
dive();
} catch (StackOverflowError e) {
System.out.println("StackOverflowError after " + depth + " calls");
}
List<long[]> hog = new ArrayList<>();
try {
while (true) {
hog.add(new long[1_000_000]);
}
} catch (OutOfMemoryError e) {
int arrays = hog.size();
hog.clear();
System.out.println("OutOfMemoryError: " + e.getMessage()
+ " after " + arrays + " arrays of 8 MB");
}
}
}StackOverflowError after 10473 calls
OutOfMemoryError: Java heap space after 507 arrays of 8 MBHow it works
- Stack: each method call gets a frame on its thread's stack (its parameters and local variables).
dive()calls itself forever with no stopping condition, so frames pile up until the stack is full, and Java throwsStackOverflowError. The exact count depends on the stack size and the JVM. - Heap: every
new long[1_000_000]takes 8 MB on the heap. The list keeps a reference to each one, so the garbage collector can't free any of them. When the heap is full, Java throwsOutOfMemoryError: Java heap space. The count depends on the heap size (try running with-Xmx64mto make it smaller). - These examples catch the errors only to show them.
hog.clear()releases the memory so the program can finish.
Causes and Fixes
| Error | Usual cause | Fix |
|---|---|---|
StackOverflowError | Recursion with a missing or wrong base case | Add or correct the base case |
StackOverflowError | Very deep but correct recursion | Rewrite as a loop (see "Recursion vs Iteration"), or increase the stack with -Xss |
StackOverflowError | Two methods calling each other, such as toString() methods that print each other | Break the cycle |
OutOfMemoryError: Java heap space | Collections that grow forever (caches, lists of logs) | Remove old entries; bound the size |
OutOfMemoryError: Java heap space | Loading a huge file into memory at once | Process it in pieces |
OutOfMemoryError: Java heap space | The program genuinely needs more memory | Raise the limit with -Xmx, for example -Xmx2g |
Why You Shouldn't Catch Errors
When an Error happens, the JVM may be in a broken state: an OutOfMemoryError can strike in the middle of any allocation, even inside library code, leaving objects half-updated. Catching it and carrying on usually leads to stranger failures later. The right response is to let the program stop, read the error, and fix the cause. Production servers are often started with -XX:+HeapDumpOnOutOfMemoryError, which saves a snapshot of the heap for analysis when memory runs out.
Common Mistakes
Recursion without a base case, or with one that's never reached. Trace a small input by hand first.
Treating OutOfMemoryError as "buy more RAM". Usually something is holding references it shouldn't.
Catching Error or Throwable to keep a program alive. It hides a broken state.
Interview Corner
What causes StackOverflowError and OutOfMemoryError?
StackOverflowError is thrown when a thread's call stack runs out of space, almost always because of infinite or excessively deep recursion. OutOfMemoryError is thrown when the JVM can't allocate an object because the heap (or another memory area) is exhausted and garbage collection can't free enough, usually because objects are still referenced, as in an ever-growing collection. Both extend Error and indicate conditions applications normally shouldn't try to catch.
Can you catch an OutOfMemoryError?
Technically yes, since it's a Throwable, but you usually shouldn't. The JVM may be in an inconsistent state, and continuing can cause unpredictable failures. It's better to fix the cause, raise the heap size if justified, or let the process restart, collecting a heap dump to investigate.
Practice
- Easy: Write a recursive
factorial(int n)with a correct base case. Then remove the base case and observe the error. - Harder: Run
Errors.javawithjava -Xmx64m Errors.javaand then with-Xmx256m. How does the number of arrays change, and why?
Key Takeaways
Was this tutorial helpful?