- Что на самом деле вызывает ошибку StackOverflow в Java?
- Причина использования StackOverflowError
- Что такое stacktrace?
- Java StackOverFlowError Causes & Solutions
- 1. StackOverFlowError
- 2. StackOverFlowError Cause
- 3. Solutions to StackOverflowError
- 3.1 Fix the Code
- 3.2 Increase Thread Stack Size (-Xss)
- How to Fix java.lang.StackOverflowError in Java
- What Causes java.lang.StackOverflowError in Java
- java.lang.StackOverflowError Example in Java
- How to fix java.lang.StackOverflowError in Java
- Inspect the stack trace
- Increase Thread Stack Size (-Xss)
- Track, Analyze and Manage Errors With Rollbar
Что на самом деле вызывает ошибку StackOverflow в Java?
StackOverflowError просто сигнализирует о том, что памяти больше нет. Он расширяет класс VirtualMachineError, что указывает на то, что JVM (виртуальная машина Java) повреждена или у нее закончились ресурсы и она не может работать.
Если у вас есть такая функция, как:
В приведенном выше коде myFunction() будет продолжать называть себя, все глубже и глубже, и когда пространство, используемое для отслеживания того, какие функции вы находитесь, заполнено, вы получаете ошибку stackoverflow. Общей причиной переполнения стека является плохой рекурсивный вызов. Как правило, это вызвано, когда ваши рекурсивные функции не имеют правильного условия завершения, поэтому он заканчивается тем, что навсегда называет себя.
Причина использования StackOverflowError
Параметры и локальные переменные выделяются в стеке. Стек обычно находится в верхнем конце вашего адресного пространства, и, поскольку он используется, он направляется к нижней части адресного пространства. У вашего процесса также есть куча, которая живет в нижней части вашего процесса. Когда вы выделяете память, эта куча может расти в верхнем конце вашего адресного пространства. Как вы можете видеть, существует вероятность того, что куча «столкнется» со стеклом. Если нет места для нового стека кадров, StackOverflowError вызывается виртуальной машиной Java (JVM).
Если стек заполнен, вы не можете нажать, если вы это сделаете, вы получите ошибку переполнения стека.
Если стек пуст, вы не можете поп, если вы это сделаете, вы получите ошибку стека стека.
Что такое stacktrace?
Столбец — очень полезный инструмент для отладки. Это список вызовов метода, в которых приложение было посередине, когда было выбрано исключение. Это очень полезно, потому что оно не только показывает вам, где произошла ошибка, но также и то, как программа оказалась в этом месте кода.
Столбец — очень полезный инструмент для отладки. Это список вызовов метода, в которых приложение было посередине, когда было выбрано исключение. Это очень полезно, потому что оно не только показывает вам, где произошла ошибка, но также и то, как программа оказалась в этом месте кода.
Java StackOverFlowError Causes & Solutions
StackOverFlowError is one of the common JVM error. In this blog post, let’s learn inner mechanics of thread stacks, reasons that can trigger StackOverFlowError and potential solutions to address this error.
1. StackOverFlowError
To gain a deeper understanding of this exception, 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 = 0 f; System.out.println("Hello"); >>
This program is very simple with the following execution code:
- main() method invoked first
- main() method invokes a() method. Inside a() method integer variable ‘x’ is initialized to value 0.
- a() method in turn invokes b() method. Inside b() method Car object constructed and assigned to variable ‘y’.
- b() method in turn invokes c() method. Inside c() method float variable ‘z’ is initialized to value 0.
Now let’s review what happens behind the scenes when the above simple program executed. Each thread in the application has its own stack. Each stack has multiple stack frames. Thread adds the methods it’s executing, primitive data types, object pointers, return values to its stack frame in the sequence order in which they got executed.
In step #1: main() method pushed into the application thread’s stack. Step #2: a() method 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 also pushed into the same stack frame. Note both data i.e. ‘0’ and variable ‘x’ pushed into thread’s stack frame.
In step #3: b() method pushed into thread’s stack. In b() method, ‘Car’ object created and assigned to variable ‘y’. A crucial point to note here is ‘Car’ object created in the heap and not in the thread’s stack. Only Car object’s reference i.e. y stored in the thread’s stack frame.
In step #4: c() method 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 the same stack frame. Note both data i.e. ‘0f’ and variable ‘z’ is pushed into thread’s stack frame.
2. StackOverFlowError Cause
As you can see thread’s stack is storing methods it’s executing, primitive data types, 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 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 be invoked an infinite number of times. In this circumstance, a() method got added to thread’s stack frame an infinite number of times. Thus, after a few thousand iterations thread’s stack size limit might exceeded. Once stack size limit exceeds, 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)
3. Solutions to StackOverflowError
There are a couple of strategies to address StackOverflowError.
3.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 that circumstance, you must fix the source code which 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 ‘ a() ’ method.
3.2 Increase Thread Stack Size (-Xss)
There might be a legitimate reason where a threads stack size needs an increment. Maybe 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’. Pass this argument when you start the application. Example:
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 & vendor.
JVM version
Thread stack size
How to Fix java.lang.StackOverflowError in Java
The java.lang.StackOverflowError is a runtime error which points to serious problems that cannot be caught by an application. The java.lang.StackOverflowError indicates that the application stack is exhausted and is usually caused by deep or infinite recursion.
What Causes java.lang.StackOverflowError in Java
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 class B , which in turn instantiates an object of class A . 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 in Java
Here is an example of java.lang.StackOverflowError thrown due to unintended recursion:
public class StackOverflowErrorExample < public void print(int myInt) < System.out.println(myInt); print(myInt); >public static void main(String[] args) < StackOverflowErrorExample soee = new StackOverflowErrorExample(); soee.print(0); >>
In this example, the recursive method print() calls itself over and over again until it reaches the maximum size of the Java thread stack since 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.print(StackOverflowErrorExample.java:3) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4)
How to fix java.lang.StackOverflowError in Java
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.print(StackOverflowErrorExample.java:3) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4) at StackOverflowErrorExample.print(StackOverflowErrorExample.java:4)
In the above trace, line number 4 can be seen repeating, which is where the recursive calls are made and causing java.lang.StackOverflowError .
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:
This will set the thread’s stack size to 4 mb which should prevent the JVM from throwing a java.lang.StackOverflowError .
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 Java error monitoring and triaging, making fixing errors easier than ever. Try it today.
«Rollbar allows us to go from alerting to impact analysis and resolution in a matter of minutes. Without it we would be flying blind.»