What is java.lang.StackOverflowError
The error java.lang.StackOverflowError
is thrown to indicate that the application’s stack was exhausted, due to deep recursion i.e your program/script recurses too deeply.
Details
The StackOverflowError
extends VirtualMachineError
class which indicates that the JVM have been or have run out of resources and cannot operate further. The VirtualMachineError
which extends the Error
class is used to indicate those serious problems that an application should not catch. A method may not declare such errors in its throw
clause because these errors are abnormal conditions that was never expected to occur.
An Example
Minimal, Complete, and Verifiable Example
:
package demo;
public class StackOverflowErrorExample {
public static void main(String[] args)
{
StackOverflowErrorExample.recursivePrint(1);
}
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if(num == 0)
return;
else
recursivePrint(++num);
}
}
Console Output
Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
.
.
.
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
Explaination
When a function call is invoked by a Java Application, a stack frame is allocated on the call stack. The stack frame
contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError
is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion
one of the most powerful general-purpose programming technique, but must be used with caution, in order for the StackOverflowError
to be avoided.
References
- Java Doc
- StackOverflowError
What is java.lang.StackOverflowError
The error java.lang.StackOverflowError
is thrown to indicate that the application’s stack was exhausted, due to deep recursion i.e your program/script recurses too deeply.
Details
The StackOverflowError
extends VirtualMachineError
class which indicates that the JVM have been or have run out of resources and cannot operate further. The VirtualMachineError
which extends the Error
class is used to indicate those serious problems that an application should not catch. A method may not declare such errors in its throw
clause because these errors are abnormal conditions that was never expected to occur.
An Example
Minimal, Complete, and Verifiable Example
:
package demo;
public class StackOverflowErrorExample {
public static void main(String[] args)
{
StackOverflowErrorExample.recursivePrint(1);
}
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if(num == 0)
return;
else
recursivePrint(++num);
}
}
Console Output
Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
.
.
.
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
Explaination
When a function call is invoked by a Java Application, a stack frame is allocated on the call stack. The stack frame
contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError
is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion
one of the most powerful general-purpose programming technique, but must be used with caution, in order for the StackOverflowError
to be avoided.
References
- Java Doc
- StackOverflowError
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 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 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:
-Xss4m
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.
Содержание
- Ошибка StackOverflowError в Java
- 1. Обзор
- 2. Кадры стека и как происходит ошибка StackOverflowError
- 3. Ошибка StackOverflowError в действии
- 4. Работа С Ошибкой StackOverflowError
- 5. Заключение
- 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
- java.lang.StackOverflowError – How to solve StackOverflowError
- 1. The Structure of StackOverflowError
- Constructors
- 2. The StackOverflowError in Java
- 3. More about the java.lang.stackoverflowerror
- 4. How to deal with the java.lang.stackoverflowerror
- 5. Additional knowledge
- 6. Download the Eclipse Project
- Like This Article? Read More From Java Code Geeks
Ошибка StackOverflowError в Java
Узнайте, как происходит одна из наиболее распространенных ошибок Java – StackOverflowError – и как ее устранить.
Автор: baeldung
Дата записи
1. Обзор
StackOverflowError может раздражать разработчиков Java, так как это одна из самых распространенных ошибок во время выполнения, с которой мы можем столкнуться.
В этой статье мы рассмотрим, как может возникнуть эта ошибка, рассмотрев различные примеры кода, а также то, как мы можем с ней справиться.
2. Кадры стека и как происходит ошибка StackOverflowError
Давайте начнем с основ. При вызове метода в стеке вызовов создается новый кадр стека. Этот кадр стека содержит параметры вызываемого метода, его локальные переменные и адрес возврата метода, т. е. точку, из которой выполнение метода должно продолжаться после возврата вызванного метода.
Создание фреймов стека будет продолжаться до тех пор, пока не будет достигнут конец вызовов методов, найденных внутри вложенных методов.
Во время этого процесса, если JVM столкнется с ситуацией, когда нет места для создания нового кадра стека, он выдаст StackOverflowError .
Наиболее распространенной причиной, по которой JVM сталкивается с этой ситуацией, является unterminated/бесконечная рекурсия – в описании Javadoc для StackOverflowError упоминается, что ошибка возникает в результате слишком глубокой рекурсии в конкретном фрагменте кода.
Однако рекурсия-не единственная причина этой ошибки. Это также может произойти в ситуации, когда приложение продолжает вызывать методы из методов до тех пор, пока стек не будет исчерпан . Это редкий случай, поскольку ни один разработчик не будет намеренно следовать плохим методам кодирования. Другой редкой причиной является наличие огромного количества локальных переменных внутри метода .
Ошибка StackOverflowError также может быть вызвана, когда приложение предназначено для циклических отношений c между классами . В этой ситуации конструкторы друг друга вызываются повторно, что приводит к возникновению этой ошибки. Это также можно рассматривать как форму рекурсии.
Другой интересный сценарий, который вызывает эту ошибку, заключается в том, что экземпляр класса создается в том же классе, что и переменная экземпляра этого класса . Это приведет к тому, что конструктор одного и того же класса будет вызываться снова и снова (рекурсивно), что в конечном итоге приведет к ошибке StackOverflowError.
В следующем разделе мы рассмотрим некоторые примеры кода, демонстрирующие эти сценарии.
3. Ошибка StackOverflowError в действии
В примере, показанном ниже, StackOverflowError будет вызван из-за непреднамеренной рекурсии, когда разработчик забыл указать условие завершения для рекурсивного поведения:
Здесь ошибка возникает во всех случаях для любого значения, переданного в метод:
Однако в следующем примере указано условие завершения, но оно никогда не выполняется, если значение -1 передается в метод calculateFactorial () , который вызывает нескончаемую/бесконечную рекурсию:
Этот набор тестов демонстрирует этот сценарий:
В данном конкретном случае ошибки можно было бы полностью избежать, если бы условие завершения было просто сформулировано как:
Вот тест, который показывает этот сценарий на практике:
Теперь давайте рассмотрим сценарий, в котором StackOverflowError возникает в результате циклических отношений между классами. Давайте рассмотрим ClassOne и classstwo , которые создают экземпляры друг друга внутри своих конструкторов, вызывая циклическую связь:
Теперь предположим, что мы попытаемся создать экземпляр Class One , как показано в этом тесте:
Это заканчивается StackOverflowError , так как конструктор Class One создает экземпляр Class Two, и конструктор classwo снова создает экземпляр ClassOne. И это повторяется до тех пор, пока он не переполнит стек.
Далее мы рассмотрим, что происходит, когда экземпляр класса создается в том же классе, что и переменная экземпляра этого класса.
Как видно из следующего примера, Владелец счета создает экземпляр в качестве переменной экземпляра Владелец совместного счета :
Когда Владелец учетной записи класс создается , a StackOverflowError выбрасывается из-за рекурсивного вызова конструктора, как показано в этом тесте:
4. Работа С Ошибкой StackOverflowError
Лучшее, что можно сделать при обнаружении StackOverflowError , – это осторожно проверить трассировку стека, чтобы определить повторяющийся шаблон номеров строк. Это позволит нам найти код, который имеет проблемную рекурсию.
Лучшее, что можно сделать при обнаружении || StackOverflowError||, – это осторожно проверить трассировку стека, чтобы определить повторяющийся шаблон номеров строк. Это позволит нам найти код, который имеет проблемную рекурсию.
Эта трассировка стека создается Бесконечной рекурсией С ручным тестом условия завершения , если мы опустим объявление ожидаемого исключения:
Здесь можно увидеть повторение строки № 5. Именно здесь выполняется рекурсивный вызов. Теперь это просто вопрос изучения кода, чтобы увидеть, правильно ли выполняется рекурсия.
Вот трассировка стека, которую мы получаем, выполняя ручной тест циклической зависимости (опять же, без ожидаемого исключения):
Эта трассировка стека показывает номера строк, которые вызывают проблему в двух классах, находящихся в циклической связи. Строка номер 9 класса Два и строка номер 9 класса Один указывают на местоположение внутри конструктора, где он пытается создать экземпляр другого класса.
После тщательной проверки кода и если ни одно из следующих действий (или любая другая логическая ошибка кода) не является причиной ошибки:
- Неправильно реализованная рекурсия (т. е. без условия завершения)
- Циклическая зависимость между классами
- Создание экземпляра класса в том же классе, что и переменная экземпляра этого класса
Было бы неплохо попытаться увеличить размер стека. В зависимости от установленной JVM размер стека по умолчанию может варьироваться.
Флаг -Xss можно использовать для увеличения размера стека либо из конфигурации проекта, либо из командной строки.
5. Заключение
В этой статье мы более подробно рассмотрели StackOverflowError , включая то, как Java-код может вызвать его, а также как мы можем диагностировать и исправить его.
Исходный код, связанный с этой статьей, можно найти на GitHub .
Источник
How to Fix java.lang.StackOverflowError in Java
Table of Contents
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:
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 :
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:
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.
Источник
java.lang.StackOverflowError – How to solve StackOverflowError
The java.lang.stackoverflowerror – StackOverflow Error in Java is thrown to indicate that the application’s stack was exhausted, due to deep recursion.
The StackOverflowError extends the VirtualMachineError class, which indicates that the JVM is broken, or it has run out of resources and cannot operate. Furthermore, the VirtualMachineError extends the Error class, which is used to indicate those serious problems that an application should not catch. A method may not declare such errors in its throw clause, because these errors are abnormal conditions that shall never occur.
Finally, the StackOverflowError exists since the 1.0 version of Java.
You can also check this tutorial in the following video:
1. The Structure of StackOverflowError
Constructors
- StackOverflowError()
Creates an instance of the StackOverflowError class, setting null as its message.
- StackOverflowError(String s)
Creates an instance of the StackOverflowError class, using the specified string as message. The string argument indicates the name of the class that threw the error.
2. The StackOverflowError in Java
When a function call is invoked by a Java application, a stack frame is allocated on the call stack. The stack frame contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion is considered as a powerful general-purpose programming technique, but must be used with caution, in order for the StackOverflowError to be avoided.
An example that throws a StackOverflowError is shown below:
In this example, we define a recursive method, called recursivePrint that prints an integer and then, calls itself, with the next successive integer as an argument. The recursion ends once we invoke the method, passing 0 as a parameter. However, in our example, we start printing numbers from 1 and thus, the recursion will never terminate.
A sample execution, using the -Xss1M flag that specifies the size of the thread stack to equal to 1MB, is shown below:
Depending on the JVM’s initial configuration, the results may differ, but eventually the StackOverflowError shall be thrown. This example is a very good example of how recursion can cause problems, if not implemented with caution.
3. More about the java.lang.stackoverflowerror
The following example demonstrates the risk of having cyclic relationships between classes:
In this example, we defined two classes, A and B . The class A contains one instance of the B class, while, the B class contains one instance of the A class. Thus, we have a circular dependency between these two classes. Furthermore, each toString method, invokes the corresponding toString method of the other class, and so on, which results in a StackOverflowError .
A sample execution is shown below:
4. How to deal with the java.lang.stackoverflowerror
- The simplest solution is to carefully inspect the stack trace and detect the repeating pattern of line numbers. These line numbers indicate the code being recursively called. Once you detect these lines, you must carefully inspect your code and understand why the recursion never terminates.
- If you have verified that the recursion is implemented correctly, you can increase the stack’s size, in order to allow a larger number of invocations. Depending on the Java Virtual Machine (JVM) installed, the default thread stack size may equal to either 512KB , or 1MB . You can increase the thread stack size using the -Xss flag. This flag can be specified either via the project’s configuration, or via the command line. The format of the -Xss argument is:
-Xss [g|G|m|M|k|K]
5. Additional knowledge
6. Download the Eclipse Project
This was a tutorial about the StackOverflowError in Java.
Last updated on Oct. 12th, 2021
Like This Article? Read More From Java Code Geeks
This site uses Akismet to reduce spam. Learn how your comment data is processed.
public class Demo
<
Demo obj2=new Demo();
public static void main(String[] args)
<
Demo obj1=new Demo();
>
Exception in thread “main” java.lang.StackOverflowError
at Demo.(Demo.java:3)
toString is pretty empty, no invokation the corresponding toString in the other class
E:Akhilclasses>javac CmdLine.java
CmdLine.java:10: error: cannot find symbol
for(i=0;i
how can i ansear yes or no and ask different questions based of respond first time programmer
if (answer.equalsIgnoreCase(“yes”)) <
System.out.println(“are you around ?”);
answer = khumbu.next();
>
if (answer.equalsIgnoreCase(“no”)) <
System.out.println(” were you in town”);
answer = khumbu.next();
>
if (answer.equalsIgnoreCase(“yes”)) <
System.out.println(“are you off tommorow?”);
answer = khumbu.next();
if (answer.equalsIgnoreCase(“yes”)) <
System.out.println(“EAT IT”);
answer = khumbu.next();
>
if (answer.equalsIgnoreCase(“no”)) <
System.out.println(“do you have siblings ?”);
answer = khumbu.next();
>
if (answer.equalsIgnoreCase(“yes”)) <
System.out.println(“name them”);
answer = khumbu.next();
>
I have a problem with my website possibly a Java coding error. I am not the developer though. The coding is overflowing on the header. Please give me a step by step correction.
I am running the company all alone now and want to have a head-start now. Any help is much appreciated.
Источник
Improve Article
Save Article
Improve Article
Save Article
StackOverflowError is an error which Java doesn’t allow to catch, for instance, stack running out of space, as it’s one of the most common runtime errors one can encounter.
The main cause of the StackOverflowError is that we haven’t provided the proper terminating condition to our recursive function or template, which means it will turn into an infinite loop.
When does StackOverflowError encountered?
When we invoke a method, a new stack frame is created on the call stack or on the thread stack size. This stack frame holds parameters of the invoked method, mostly the local variables and the return address of the method. The creation of these stack frames will be iterative and will be stopped only when the end of the method invokes is found in the nested methods. In amidst of this process, if JVM runs out of space for the new stack frames which are required to be created, it will throw a StackOverflowError.
For example: Lack of proper or no termination condition. This is mostly the cause of this situation termed as unterminated or infinite recursion.
Given below is the implementation of infinite recursion:
public
class
StackOverflowErrorClass {
static
int
i =
0
;
public
static
int
printNumber(
int
x)
{
i = i +
2
;
System.out.println(i);
return
i + printNumber(i +
2
);
}
public
static
void
main(String[] args)
{
StackOverflowErrorClass.printNumber(i);
}
}
Runtime Error:
RunTime Error in java code :- Exception in thread “main” java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:597)
at java.io.PrintStream.println(PrintStream.java:736)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:13)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:14)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:14)
.
.
.
Note: Please run this on your system to see an error thrown, due to the stack size, this may not show error on online IDE.
How to fix StackOverflowError?
- Avoiding repetitive calls: Try to introduce a proper terminating condition or some condition for the recursive calls to ensure that it terminates.
Given below is the implementation with proper terminating condition:
public
class
stackOverflow {
static
int
i =
0
;
public
static
int
printNumber(
int
x)
{
i = i +
2
;
System.out.println(i);
if
(i ==
10
)
return
i;
return
i + printNumber(i +
2
);
}
public
static
void
main(String[] args)
{
stackOverflow.printNumber(i);
}
}
- Increasing the Stack Size: The second method could be, if you notice that it’s implemented correctly still we see an error, then we can avoid that only by increasing the Stack Size in order to store the required number of recursive calls. This is achieved by changing the settings of the compiler.
Cyclic Relationships between classes is the relationship caused when two different classes instantiate each other inside their constructors.
StackOverflowError is encountered because the constructor of Class A1 is instantiating Class A2, and the constructor of Class A2 is again instantiating Class A1, and it occurs repeatedly until we see StackOverflow. This error is mainly due to the bad calling of constructors, that is, calling each other, which is not even required, and also it doesn’t hold any significance, so we can just avoid introducing them in the codes.
Given below is the implementation of Cyclic Relationships Between Classes:
public
class
A1 {
public
A2 type2;
public
A1()
{
type2 =
new
A2();
}
public
static
void
main(String[] args)
{
A1 type1 =
new
A1();
}
}
class
A2 {
public
A1 type1;
public
A2()
{
type1 =
new
A1();
}
}
Runtime Error:
RunTime Error in java code :- Exception in thread “main” java.lang.StackOverflowError
at A2.(A1.java:32)
at A1.(A1.java:13)
at A2.(A1.java:32)
.
.
.Note: This will keep repeating, Infinite Recursion is seen by these infinite cyclic calls.
StackOverflowError в Java
1. обзор
StackOverflowError может раздражать разработчиков Java, поскольку это одна из самых распространенных ошибок времени выполнения, с которыми мы можем столкнуться.
В этой статье мы увидим, как может возникать эта ошибка, на различных примерах кода и узнаем, как с ней бороться.
2. Фреймы стека и как происходитStackOverflowError
Давайте начнем с основ. When a method is called, a new stack frame gets created on the call stack. Этот кадр стека содержит параметры вызванного метода, его локальные переменные и адрес возврата метода, т.е. точка, с которой выполнение метода должно продолжаться после возврата вызванного метода.
Создание кадров стека будет продолжаться до тех пор, пока не будет достигнут конец вызовов методов, найденных во вложенных методах.
Во время этого процесса, если JVM обнаруживает ситуацию, когда нет места для создания нового кадра стека, она выдастStackOverflowError.
Наиболее частая причина, по которой JVM может столкнуться с этой ситуацией, —unterminated/infinite recursion — в описании Javadoc дляStackOverflowError упоминается, что ошибка возникает в результате слишком глубокой рекурсии в конкретном фрагменте кода.
Однако рекурсия не является единственной причиной этой ошибки. Это также может произойти в ситуации, когда приложение хранитcalling methods from within methods until the stack is exhausted. Это редкий случай, так как ни один разработчик не будет намеренно следовать плохой практике кодирования Другая редкая причина —having a vast number of local variables inside a method.
StackOverflowError также может быть выброшено, если приложение разработано для использованияcyclic relationships between classes. В этой ситуации конструкторы друг друга вызывают неоднократно, что приводит к возникновению этой ошибки. Это также можно рассматривать как форму рекурсии.
Другой интересный сценарий, который вызывает эту ошибку, — этоclass is being instantiated within the same class as an instance variable of that class. Это приведет к тому, что конструктор одного и того же класса будет вызываться снова и снова (рекурсивно), что в конечном итоге приведет кStackOverflowError.
В следующем разделе мы рассмотрим несколько примеров кода, демонстрирующих эти сценарии.
3. StackOverflowError в действии
В примере, показанном ниже,StackOverflowError будет выброшено из-за непреднамеренной рекурсии, когда разработчик забыл указать условие завершения для рекурсивного поведения:
public class UnintendedInfiniteRecursion {
public int calculateFactorial(int number) {
return number * calculateFactorial(number - 1);
}
}
Здесь ошибка выдается во всех случаях для любого значения, переданного в метод:
public class UnintendedInfiniteRecursionManualTest {
@Test(expected = StackOverflowError.class)
public void givenPositiveIntNoOne_whenCalFact_thenThrowsException() {
int numToCalcFactorial= 1;
UnintendedInfiniteRecursion uir
= new UnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
}
@Test(expected = StackOverflowError.class)
public void givenPositiveIntGtOne_whenCalcFact_thenThrowsException() {
int numToCalcFactorial= 2;
UnintendedInfiniteRecursion uir
= new UnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
}
@Test(expected = StackOverflowError.class)
public void givenNegativeInt_whenCalcFact_thenThrowsException() {
int numToCalcFactorial= -1;
UnintendedInfiniteRecursion uir
= new UnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
}
}
Однако в следующем примере указано условие завершения, но оно никогда не выполняется, если значение-1 передается методуcalculateFactorial(), что вызывает незавершенную / бесконечную рекурсию:
public class InfiniteRecursionWithTerminationCondition {
public int calculateFactorial(int number) {
return number == 1 ? 1 : number * calculateFactorial(number - 1);
}
}
Этот набор тестов демонстрирует этот сценарий:
public class InfiniteRecursionWithTerminationConditionManualTest {
@Test
public void givenPositiveIntNoOne_whenCalcFact_thenCorrectlyCalc() {
int numToCalcFactorial = 1;
InfiniteRecursionWithTerminationCondition irtc
= new InfiniteRecursionWithTerminationCondition();
assertEquals(1, irtc.calculateFactorial(numToCalcFactorial));
}
@Test
public void givenPositiveIntGtOne_whenCalcFact_thenCorrectlyCalc() {
int numToCalcFactorial = 5;
InfiniteRecursionWithTerminationCondition irtc
= new InfiniteRecursionWithTerminationCondition();
assertEquals(120, irtc.calculateFactorial(numToCalcFactorial));
}
@Test(expected = StackOverflowError.class)
public void givenNegativeInt_whenCalcFact_thenThrowsException() {
int numToCalcFactorial = -1;
InfiniteRecursionWithTerminationCondition irtc
= new InfiniteRecursionWithTerminationCondition();
irtc.calculateFactorial(numToCalcFactorial);
}
}
В этом конкретном случае ошибки можно было бы полностью избежать, если бы условие завершения было просто сформулировано как:
public class RecursionWithCorrectTerminationCondition {
public int calculateFactorial(int number) {
return number <= 1 ? 1 : number * calculateFactorial(number - 1);
}
}
Вот тест, который демонстрирует этот сценарий на практике:
public class RecursionWithCorrectTerminationConditionManualTest {
@Test
public void givenNegativeInt_whenCalcFact_thenCorrectlyCalc() {
int numToCalcFactorial = -1;
RecursionWithCorrectTerminationCondition rctc
= new RecursionWithCorrectTerminationCondition();
assertEquals(1, rctc.calculateFactorial(numToCalcFactorial));
}
}
Теперь давайте рассмотрим сценарий, в которомStackOverflowError возникает в результате циклических отношений между классами. Давайте рассмотримClassOne иClassTwo, которые создают экземпляры друг друга внутри своих конструкторов, вызывая циклическую связь:
public class ClassOne {
private int oneValue;
private ClassTwo clsTwoInstance = null;
public ClassOne() {
oneValue = 0;
clsTwoInstance = new ClassTwo();
}
public ClassOne(int oneValue, ClassTwo clsTwoInstance) {
this.oneValue = oneValue;
this.clsTwoInstance = clsTwoInstance;
}
}
public class ClassTwo {
private int twoValue;
private ClassOne clsOneInstance = null;
public ClassTwo() {
twoValue = 10;
clsOneInstance = new ClassOne();
}
public ClassTwo(int twoValue, ClassOne clsOneInstance) {
this.twoValue = twoValue;
this.clsOneInstance = clsOneInstance;
}
}
Теперь предположим, что мы пытаемся создать экземплярClassOne, как показано в этом тесте:
public class CyclicDependancyManualTest {
@Test(expected = StackOverflowError.class)
public void whenInstanciatingClassOne_thenThrowsException() {
ClassOne obj = new ClassOne();
}
}
В итоге получаетсяStackOverflowError, поскольку конструкторClassOne создает экземплярClassTwo,, а конструкторClassTwo снова создает экземплярClassOne.. И это происходит неоднократно, пока он не переполнится. стек.
Далее мы рассмотрим, что происходит, когда создается экземпляр класса в том же классе, что и переменная экземпляра этого класса.
Как видно в следующем примере,AccountHolder создает экземпляр переменной экземпляраjointAccountHolder:
public class AccountHolder {
private String firstName;
private String lastName;
AccountHolder jointAccountHolder = new AccountHolder();
}
Когда создается экземпляр классаAccountHolder,, вызываетсяStackOverflowError из-за рекурсивного вызова конструктора, как показано в этом тесте:
public class AccountHolderManualTest {
@Test(expected = StackOverflowError.class)
public void whenInstanciatingAccountHolder_thenThrowsException() {
AccountHolder holder = new AccountHolder();
}
}
4. Работа сStackOverflowError
Лучшее, что можно сделать при обнаруженииStackOverflowError, — это осторожно изучить трассировку стека, чтобы определить повторяющийся шаблон номеров строк. Это позволит нам найти код с проблемной рекурсией.
Давайте рассмотрим несколько трассировок стека, вызванных примерами кода, которые мы видели ранее.
Эта трассировка стека создаетсяInfiniteRecursionWithTerminationConditionManualTest, если мы опускаем объявление исключенияexpected:
java.lang.StackOverflowError
at c.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
at c.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
at c.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
at c.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
Здесь строка № 5 видна повторяющейся. Это где рекурсивный вызов делается. Теперь остается просто изучить код, чтобы убедиться, что рекурсия выполнена правильно.
Вот трассировка стека, которую мы получаем, выполняяCyclicDependancyManualTest (опять же, без исключенияexpected):
java.lang.StackOverflowError
at c.b.s.ClassTwo.(ClassTwo.java:9)
at c.b.s.ClassOne.(ClassOne.java:9)
at c.b.s.ClassTwo.(ClassTwo.java:9)
at c.b.s.ClassOne.(ClassOne.java:9)
Эта трассировка стека показывает номера строк, которые вызывают проблему в двух классах, которые находятся в циклическом отношении. Строка номер 9ClassTwo и строка номер 9ClassOne указывают на место внутри конструктора, где он пытается создать экземпляр другого класса.
Как только код тщательно проверен, и если ни одно из следующего (или любая другая логическая ошибка кода) не является причиной ошибки:
-
Неправильно реализованная рекурсия (т.е. без условия прекращения)
-
Циклическая зависимость между классами
-
Создание класса внутри того же класса, что и переменная экземпляра этого класса
Было бы неплохо попробовать увеличить размер стека. В зависимости от установленной JVM размер стека по умолчанию может варьироваться.
Флаг-Xss можно использовать для увеличения размера стека либо из конфигурации проекта, либо из командной строки.
5. Заключение
В этой статье мы более подробно рассмотрелиStackOverflowError, включая то, как код Java может вызывать это, и как мы можем диагностировать и исправить это.
Исходный код, относящийся к этой статье, можно найтиover on GitHub.
What is java.lang.StackOverflowError
The error java.lang.StackOverflowError
is thrown to indicate that the application’s stack was exhausted, due to deep recursion i.e your program/script recurses too deeply.
Details
The StackOverflowError
extends VirtualMachineError
class which indicates that the JVM have been or have run out of resources and cannot operate further. The VirtualMachineError
which extends the Error
class is used to indicate those serious problems that an application should not catch. A method may not declare such errors in its throw
clause because these errors are abnormal conditions that was never expected to occur.
An Example
Minimal, Complete, and Verifiable Example
:
package demo;
public class StackOverflowErrorExample {
public static void main(String[] args)
{
StackOverflowErrorExample.recursivePrint(1);
}
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if(num == 0)
return;
else
recursivePrint(++num);
}
}
Console Output
Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
.
.
.
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
Explaination
When a function call is invoked by a Java Application, a stack frame is allocated on the call stack. The stack frame
contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError
is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion
one of the most powerful general-purpose programming technique, but must be used with caution, in order for the StackOverflowError
to be avoided.
References
- Java Doc
- StackOverflowError
What is java.lang.StackOverflowError
The error java.lang.StackOverflowError
is thrown to indicate that the application’s stack was exhausted, due to deep recursion i.e your program/script recurses too deeply.
Details
The StackOverflowError
extends VirtualMachineError
class which indicates that the JVM have been or have run out of resources and cannot operate further. The VirtualMachineError
which extends the Error
class is used to indicate those serious problems that an application should not catch. A method may not declare such errors in its throw
clause because these errors are abnormal conditions that was never expected to occur.
An Example
Minimal, Complete, and Verifiable Example
:
package demo;
public class StackOverflowErrorExample {
public static void main(String[] args)
{
StackOverflowErrorExample.recursivePrint(1);
}
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if(num == 0)
return;
else
recursivePrint(++num);
}
}
Console Output
Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
.
.
.
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
Explaination
When a function call is invoked by a Java Application, a stack frame is allocated on the call stack. The stack frame
contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError
is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion
one of the most powerful general-purpose programming technique, but must be used with caution, in order for the StackOverflowError
to be avoided.
References
- Java Doc
- StackOverflowError