StackOverflowError in Java
Missing base case or too-deep recursion exhausts the stack.
A full stack
Each call adds a frame, and the call stack has a limited size. Recursion without a reachable base case, or recursion that's simply too deep, keeps pushing frames until the JVM throws **StackOverflowError**.
static int forever(int n) {
return forever(n + 1); // no base case
}
// forever(0) -> StackOverflowErrorPing-pong
Two methods call each other. What happens?
static int ping(int n) {
return pong(n + 1);
}
static int pong(int n) {
return ping(n + 1);
}
void main() {
System.out.println(ping(0));
}Runs foreverThrows StackOverflowErrorCompile error
Show the answer
StackOverflowError. Recursion doesn't have to be one method calling itself: ping calls pong calls ping... Each call pushes a frame, and none ever returns.
The base case you skip over
A base case only helps if the recursion reaches it. fact(0) goes to -1, -2, -3... and never equals 1. Use n <= 1 so 0 (and anything smaller) stops too.
static long fact(int n) {
if (n == 1) return 1; // 0 skips it
return n * fact(n - 1);
}
// fix: if (n <= 1) return 1;An Error, not an Exception
StackOverflowError extends VirtualMachineError, which extends **Error. It's unchecked**: no throws clause needed. Errors signal serious problems; it means fix the bug, not catch it and carry on.
Throwable
āā Exception ...
āā Error
āā VirtualMachineError
āā StackOverflowErrorLoops vs calls
A while (true) loop that only increments a counter runs forever. Will it ever throw StackOverflowError?
Think about it, then reveal the answer
No. A loop reuses the same frame, so the stack never grows; it just runs forever. Only calls push frames. That's also why turning recursion into a loop cures overflow.
Too deep, not wrong
static long sum(int n) {
if (n == 0) return 0;
return n + sum(n - 1);
}
// sum(10_000_000) -> overflowCorrect logic, but 10 million frames won't fit. Java doesn't optimize tail calls, so every call costs a frame.
static long sum(int n) {
long total = 0;
for (int i = 1; i <= n; i++)
total += i;
return total;
}Same answer in a single frame, at any size.
In real projects
Recursive parsers can be attacked with absurdly deep input (JSON nested thousands of levels) to crash servers with StackOverflowError, so real parsers enforce depth limits. You can raise the stack size with java -Xss4m, but rewriting deep recursion as a loop is the robust fix.
Key takeaways
- Causes: missing or unreachable base case, or very deep recursion
- StackOverflowError extends Error (via VirtualMachineError), so it's unchecked
- Fix the base case, or rewrite very deep recursion as a loop
- Java doesn't optimize tail calls, so even 'simple' recursion uses a frame per call
Stack Overflow, the famous programming Q&A site launched in 2008, is named after exactly this error.
Practice questions
What does this print?
static int down(int n) {
return down(n - 1);
}
void main() {
System.out.println(down(5));
}- 0
- Throws StackOverflowError
- Compile error
- Throws OutOfMemoryError
Check your answer
Throws StackOverflowError. There is no base case. Each call pushes another frame until the stack is full and the JVM throws StackOverflowError.
Three of these can cause StackOverflowError. Which one can't?
- A recursive method with no base case
- Two methods that call each other forever
- A while (true) loop that only increments a counter
- Correct recursion that goes 10 million calls deep
Check your answer
A while (true) loop that only increments a counter. A loop reuses the same frame, so it never grows the stack; it just runs forever. The others all keep pushing new frames.