Skip to content

Latest commit

 

History

History
202 lines (157 loc) · 6.7 KB

how-to-troubleshoot-java-stackoverflowerror.md

File metadata and controls

202 lines (157 loc) · 6.7 KB
title authorSlug authorDisplayName tags publicationDate description image imageAlt browserTitle type
How to troubleshoot Java StackOverflowError
yashesvinee-v
Yashesvinee V
tutorial
Java
troubleshooting
October 16, 2021
Learn how to error handle the Java StackOverflowError
Sourcegraph Learn
StackOverflowError in Java error handling
posts

The StackOverflowError is one of the most common runtime errors one can encounter in Java. This error occurs when we haven’t provided the proper terminating condition to our recursive function that results in an infinite loop.

When we call a method, a new stack frame is created on the call stack. This stack frame holds parameters of the called method, mostly the local variables and the return address of the method. The creation of these stack frames is iterative. During this process, if the Java Virtual Machine (JVM) runs out of space for the new stack frames, it throws a StackOverflowError.

Reproducing the error

In our example Java file, we’ll define a recursive method, called recursion() that prints an integer and then calls itself with the successive integer as its argument.

<PrismSyntaxHighlighter input={`public class Main {

public static void recursion(int num) {
    System.out.println("Number: " + num);
     
    if(num == 0)
        return;
    else
        recursion(++num);
}
 
public static void main(String[] args) {
    Main.recursion(1);
}

}`} language='java' />

When we compile and run the program, it starts printing numbers starting from 1 on, and thus the recursion never terminates. Depending on the JVM, the results may differ, but eventually the StackOverflowError is thrown.

You may need to scroll through considerable output to find the error.

A program that has cyclic relationships between classes is also another situation where the StackOverflowError commonly occurs. Here's an example:

<PrismSyntaxHighlighter input={`public class A { public B type2; public A() { type2 = new B(); // Constructor of B is called hence object of A is created }

public static void main(String[] args)
{
		A type1 = new A();    // Cycle is started by invoking constructor of class A
}

}

class B { public A type1; public B() { type1 = new A(); // Constructor of A is called hence object of A is created } }`} language='java' />

Once we compile and run the above program, we'll receive output similar to the following.

Cyclic relationships between classes is the result of two different classes instantiating each other inside their constructors. In the example, classes A and B instantiate each other in their contructors repeatedly until we get a StackOverflowError.

Now, let's review the solution to prevent this error.

Add a terminating condition

We must carefully inspect the stack, trace and detect the repetitive calls and try to introduce a proper terminating condition to ensure that the recursion terminates. We can avoid the error in the first example by adding a terminating condition.

<PrismSyntaxHighlighter input={`public class Main {

public static void recursion(int num) {
    System.out.println("Number: " + num);
     
    if(num == 0)
        return;
    if(num == 5)
        return;
    else
        recursion(++num);
}
  
public static void main(String[] args) {
    Main.recursion(1);
}

}`} language='java' />

This program will print the numbers from 1 to 5:

Your terminating condition should make sense for the program you are building. Thinking through what would stop a given loop will make your program more effective and help you avoid the StackOverflowError.

Avoid unnecessary constructor calls

In our second example of cyclic relationships, the error is mainly due to unecessary constructor calls, so work to avoid introducing them in your code. Another way of resolving this is to specify one as the parent and the other as the dependent. We can construct class A as the parent class and make class B the child, as demonstrated in the rewrite of the program below.

<PrismSyntaxHighlighter input={public class A { public B type2; public A() { this.type2 = new B(this); } public static void main(String[] args) { A type1 = new A(); } } class B { public A type1; public B(A parent) { this.type1 = parent; } }} language='java' />

This solution prevents the recursive constructor calls and avoids the error.

Increasing the stack size

If we expect we will need a lot of compute power ro tun our program, and anticipate a high number of loops or other ongoing processes, we can increase the stack’s size in order to allow a larger number of invocations. The default thread stack size may vary depending on the JVM installed. We can increase this stack size by using the -Xss flag.

The format of the -Xss argument is as follows.

This introduces the flag, and expects the size of the stack to be in gigabytes, megabytes, or kilobytes.

For example, the following command sets the default stack size to 10 megabytes.

This argument needs to be passed when you start the application and can be specified either via the project’s configuration, or the command line.

It is worth noting that computer memory is finite and it is generally recommended to focus on optimizing your program over increasing stack size unless you have a specific use case.

Learn more

Search across open source Java repositories that have the StackOverflowError to understand the message more and review it in context.

Check out more Sourcegraph Learn tutorials on Java.