Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

StackOverFlow Error: Causes and Solutions

DZone's Guide to

StackOverFlow Error: Causes and Solutions

Want to learn more about the potential causes and solutions to the StackOverFlowError in your JVM project? Check out this post to learn more.

· Java Zone ·
Free Resource

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

StackOverFlowError is one of the common confronted JVM errors. In this blog post, we will look at the inner mechanics of thread stacks, reasons that can trigger StackOverFlowError, and potential solutions to address this error.

To gain deeper understanding into 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, the integer variable ‘x’ is initialized to value 0.
  3.  a() method in turn invokes b() method. Inside b() method, the Car object is constructed and assigned to variable ‘y.'
  4.  b() method in turn invokes the c() method. Inside the c() method, the float variable ‘z’ is initialized to value 0.

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

thread-stack-frame-1

Fig 1: Thread’s Stack frame

Step #1: main() method is pushed into the application thread’s stack.

Step #2: a() method is pushed into 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 into the same stack frame. Note that both data, i.e. ‘0’ and variable ‘x,' is pushed into thread’s stack frame.

Step #3: b() method is pushed into thread’s stack. In the b() method, the Car object is created and assigned to variable ‘y.' A crucial point to note here is that the ‘Car’ object is created in the heap and not in the thread’s stack. Only the Car object’s reference, i.e. y, is stored in the thread’s stack frame.

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

Once each method’s execution is completed, then the method and the variables/object pointers are stored in the stack frame are removed, as shown in Fig 2.

thread-stack-frame-2

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 is thrown. Let’s look at the below buggy program, which will result in a  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, the main() method invokes a()  method. a() method recursively calls itself. This implementation will cause  a() method to be invoked infinite number of times. In this circumstance, a() method will be added to thread’s stack frame infinite number of times. Thus, after a few thousand iterations, thread’s stack size limit would be exceeded. Once stack size limit is exceeded, it will result 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)


stackOverflowError

Fig 3: StackOverflowError progression

What Are the Solutions to StackOverflowError?

There are couple of strategies to address  StackOverflowError.

1. Fix the Code

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

2. Increase Thread Stack Size (-Xss)

There might be legitimate reason where a threads stack size needs to be increased. Maybe thread has to execute large number of methods or lot of local variables/created in the methods thread has been executing? In such circumstances, you can increase the thread’s stack size using the JVM argument: ‘-Xss." This argument needs to be passed when you start the application. Example:

-Xss2m


This will set the thread’s stack size to 2 mb.

It might bring a question: what is the default thread’s stack size? Default thread stack size varies based on your operating system, Java version, and vendor.

JVM version

Thread stack size

Sparc 32-bit JVM

512k

Sparc 64-bit JVM

1024k

x86 Solaris/Linux 32-bit JVM

320K

x86 Solaris/Linux 64-bit JVM

1024K

Windows 32-bit JVM

320K

Windows 64-bit JVM

1024K

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

Topics:
java ,stackoverflowerror

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}