StackOverFlowError: Causes & solutions

Share
  • November 20, 2018

StackOverFlowError is one of the commonly confronted JVM error. In this blog post, let’s learn the inner mechanics of thread stacks. We will explore the reasons that trigger StackOverFlowError and potential solutions to address this error.

To gain deeper understanding in to StackOverFlowError, let’s review this simple program:

public class SimpleExample {

	public static void main(String args[]) {
		
		a();
	}	

	public static void a() {

		int x = 0;
		b();
	}

	public static void b() {

		Car y = new Car();		
		c();
	}

	public static void c() {

		float z = 0f;
		System.out.println("Hello");
	}
}

This program is very simple with the following execution code:

  1. main() method is invoked first
  2. main() method invokes a() method. Inside a() method integer variable ‘x’ is initialized to value 0.
  3. a() method in turn invokes b() method. Inside b() method Car object is constructed and assigned to variable ‘y’.
  4. b() method in turn invokes c() method. Inside c() method float variable ‘z’ is initialized to value 0.

SEE ALSO: Recent changes and what’s next for Java: “OpenJDK is the future of Java”

Now, let’s review what happens behind the scenes when we execute the above program. Each thread in the application has its own stack. Each stack has multiple stack frames. Thread adds the methods it is executing, primitive data types, object pointers, return values to its stack frame in the sequence order in which they are executed.

java

Fig 1: Thread’s Stack frame

In step #1: main() method pushes in to the application thread’s stack.

In step #2: a() method pushes in to application thread’s stack. In a() method, primitive data type ‘int’ is defined with value 0 and assigned to variable x. This information is also pushed in to same stack frame. Note both data i.e. ‘0’ and variable ‘x’ is pushed in to thread’s stack frame.

In step #3: b() method pushes in to thread’s stack. In b() method, ‘Car’ object is created and assigned to variable ‘y’. Crucial point to note here is ‘Car’ object is created in the heap and not in the thread’s stack. Only Car object’s reference i.e. y is stored in the thread’s stack frame.

In step #4: c() method pushes in to thread’s stack. In c() method, primitive data type ‘float’ is defined with value 0f and assigned to variable z. This information also pushes in to same stack frame. Note both data i.e. ‘0f’ and variable ‘z’ is pushed in to thread’s stack frame.

Once each method’s execution completes, then method and the variables/object pointers (stored in the stack frame) are removed as show in Fig 2.

java

Fig 2: Thread’s stack frame after executing methods

What causes StackOverflowError?

As you can see, thread’s stack is storing methods it’s executing, primitive datatypes, variables, object pointers and return values. All of these consume memory. If thread’s stack sizes grow beyond the allocated memory limit, then StackOverflowError occurs. Let’s look at the below buggy program, which will result in StackOverflowError:

public class SOFDemo {

	public static void a() {
			
		// Buggy line. It will cause method a() to be called infinite number of times.
		a();		
	}	
	
	public static void main(String args[]) {
		
		a();
	}
}

In this program main() method invokes a() method. a() method recursively calls itself. This implementation will cause a() method to invoke an infinite number of times. In this circumstance a() method will add to thread’s stack frame infinite number of times. Thus, after few thousand iterations, it would exceed the thread’s stack size limit. Exceeding the stack size limit results in ‘StackOverflowError’:

Exception in thread "main" java.lang.StackOverflowError
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
	at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
java

Fig 3: StackOverflowError progression

What are the solutions to StackOverflowError?

There are a couple of strategies to address StackOverflowError.

SEE ALSO: Remote debugging for Java applications

1. Fix the code

Because of a non-terminating recursive call (as shown in above example), threads stack size can grow to a large size. In those circumstance, you must fix the source code causing recursive looping. When ‘StackOverflowError’ occurs, it prints the stacktrace of the code that it was recursively executing. This code is a good pointer to start debugging and fixing the issue. So, in the above example it’s ‘a()’  method.

2. Increase Thread Stack Size (-Xss)

Let us explore the legitimate reasons why a thread’s stack size needs to increase. Maybe the thread has to execute a large number of methods or lot of local variables/created in the methods thread has been executing. In such circumstance, you can increase the thread’s stack size using the JVM argument: ‘-Xss’. This argument needs to pass when you start the application.

Example:

-Xss2m

This sets the thread’s stack size to 2 mb.

You might wonder, what is the default thread’s stack size? As for this, default thread stack size varies based on your operating system, Java version, and vendor.

The post StackOverFlowError: Causes & solutions appeared first on JAXenter.

Source : JAXenter