The java.lang.StackOverflowError
is a runtime error which indicates that the application stack is exhausted. This is usually caused by deep or infinite recursion.
To put it more simply, imagine a to-do list where each task keeps adding a new sub-task to the list. If this goes on indefinitely, the list eventually becomes too long for the sheet of paper. This is essentially what happens to cause a StackOverflowError
in Java, where too many recursive method calls exceed the stack limit.
What Causes java.lang.StackOverflowError
The java.lang.StackOverflowError
occurs when the application stack continues to grow until it reaches the maximum limit. Some of the most common causes for a java.lang.StackOverflowError
are:
- Deep or infinite recursion: If a method calls itself recursively without a terminating condition.
- Cyclic relationships between classes: If a class
A
instantiates an object of classB
, which in turn instantiates an object of classA
. This can be considered as a form of recursion. - Memory intensive applications: Applications that rely on resource heavy objects such as XML documents, GUI or java2D classes.
java.lang.StackOverflowError Example
Here is an example of java.lang.StackOverflowError
thrown due to infinite recursion:
public class StackOverflowErrorExample {
public void decrementAndPrint(int myInt) {
System.out.println(myInt--);
decrementAndPrint(myInt); //Recursively calling method without terminating condition
}
public static void main(String[] args) {
StackOverflowErrorExample soee = new StackOverflowErrorExample();
soee.decrementAndPrint(5);
}
}
In this example, the recursive method decrementAndPrint()
calls itself over and over again until it reaches the maximum size of the Java thread stack. This is because a terminating condition is not provided for the recursive calls. When the maximum size of the stack is reached, the program exits with a java.lang.StackOverflowError
:
Exception in thread "main" java.lang.StackOverflowError
at java.base/sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:564)
at java.base/java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:585)
at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:301)
at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:290)
at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:131)
at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:208)
at java.base/java.io.BufferedWriter.flushBuffer(BufferedWriter.java:120)
at java.base/java.io.PrintStream.writeln(PrintStream.java:722)
at java.base/java.io.PrintStream.println(PrintStream.java:938)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:3)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
How to Fix java.lang.StackOverflowError
Inspect the stack trace
Carefully inspecting the error stack trace and looking for the repeating pattern of line numbers enables locating the line of code with the recursive calls. When the line is identified, the code should be examined and fixed by specifying a proper terminating condition. As an example, the error stack trace seen earlier can be inspected:
at java.base/java.io.PrintStream.writeln(PrintStream.java:722)
at java.base/java.io.PrintStream.println(PrintStream.java:938)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:3)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.decrementAndPrint(StackOverflowErrorExample.java:4)
In the above trace, line number 4 can be seen repeating, which is where the recursive calls are made. The code can then be updated to provide a proper terminating condition for the recursive calls:
public class StackOverflowErrorExample {
public void decrementAndPrint(int myInt) {
System.out.println(myInt--);
if (myInt >= 0) { //Adding terminating condition for recursive calls
decrementAndPrint(myInt);
}
}
public static void main(String[] args) {
StackOverflowErrorExample soee = new StackOverflowErrorExample();
soee.decrementAndPrint(5);
}
}
Here, a check is added to ensure that the decrementAndPrint()
method is only called till the integer myInt
reaches a value of 0. This provides a terminating condition for the recursive calls, which fixes the StackOverflowError
and produces the correct output as expected:
5
4
3
2
1
0
Increase Thread Stack Size (-Xss)
If the code has been updated to implement correct recursion and the program still throws a java.lang.StackOverflowError
, the thread stack size can be increased to allow a larger number of invocations. Increasing the stack size can be useful, for example, when the program involves calling a large number of methods or using lots of local variables.
The stack size can be increased by changing the -Xss
argument on the JVM, which can be set when starting the application. Here is an example:
-Xss4m
This will set the thread’s stack size to 4 mb.
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing errors easier than ever. Try it today!