Java lang stackoverflowerror null
The StackOverflowError in Java
Last modified: October 3, 2019
I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:
In the 9 years of running Baeldung, I’ve never, ever done a «sale».
But. we’ve also not been through anything like this pandemic either.
And, if making my courses more affordable for a while is going to help a company stay in business, or a developer land a new job, make rent or be able to provide for their family — then it’s well worth doing.
Effective immediately, all Baeldung courses are 33% off their normal prices!
You’ll find all three courses in the menu, above, or here.
1. Overview
StackOverflowError can be annoying for Java developers, as it’s one of the most common runtime errors we can encounter.
In this article, we’ll see how this error can occur by looking at a variety of code examples as well as how we can deal with it.
2. Stack Frames and How StackOverflowError Occurs
Let’s start with the basics. When a method is called, a new stack frame gets created on the call stack. This stack frame holds parameters of the invoked method, its local variables and the return address of the method i.e. the point from which the method execution should continue after the invoked method has returned.
The creation of stack frames will continue until it reaches the end of method invocations found inside nested methods.
During this process, if JVM encounters a situation where there is no space for a new stack frame to be created, it will throw a StackOverflowError.
The most common cause for the JVM to encounter this situation is unterminated/infinite recursion – the Javadoc description for StackOverflowError mentions that the error is thrown as a result of too deep recursion in a particular code snippet.
However, recursion is not the only cause for this error. It can also happen in a situation where an application keeps calling methods from within methods until the stack is exhausted. This is a rare case since no developer would intentionally follow bad coding practices. Another rare cause is having a vast number of local variables inside a method.
The StackOverflowError can also be thrown when an application is designed to have cyclic relationships between classes. In this situation, the constructors of each other are getting called repetitively which causes this error to be thrown. This can also be considered as a form of recursion.
Another interesting scenario that causes this error is if a class is being instantiated within the same class as an instance variable of that class. This will cause the constructor of the same class to be called again and again (recursively) which eventually results in a StackOverflowError.
In the next section, we’ll look at some code examples that demonstrate these scenarios.
3. StackOverflowError in Action
In the example shown below, a StackOverflowError will be thrown due to unintended recursion, where the developer has forgotten to specify a termination condition for the recursive behavior:
Here, the error is thrown on all occasions for any value passed into the method:
However, in the next example a termination condition is specified but is never being met if a value of -1 is passed to the calculateFactorial() method, which causes unterminated/infinite recursion:
This set of tests demonstrates this scenario:
In this particular case, the error could have been completely avoided if the termination condition was simply put as:
Here’s the test that shows this scenario in practice:
Now let’s look at a scenario where the StackOverflowError happens as a result of cyclic relationships between classes. Let’s consider ClassOne and ClassTwo, which instantiate each other inside their constructors causing a cyclic relationship:
Now let’s say that we try to instantiate ClassOne as seen in this test:
This ends up with a StackOverflowError since the constructor of ClassOne is instantiating ClassTwo, and the constructor of ClassTwo again is instantiating ClassOne. And this repeatedly happens until it overflows the stack.
Next, we will look at what happens when a class is being instantiated within the same class as an instance variable of that class.
As seen in the next example, AccountHolder instantiates itself as an instance variable jointAccountHolder:
When the AccountHolder class is instantiated, a StackOverflowError is thrown due to the recursive calling of the constructor as seen in this test:
4. Dealing With StackOverflowError
The best thing to do when a StackOverflowError is encountered is to inspect the stack trace cautiously to identify the repeating pattern of line numbers. This will enable us to locate the code that has problematic recursion.
Let’s examine a few stack traces caused by the code examples we saw earlier.
This stack trace is produced by InfiniteRecursionWithTerminationConditionManualTest if we omit the expected exception declaration:
Here, line number 5 can be seen repeating. This is where the recursive call is being done. Now it’s just a matter of examining the code to see if the recursion is done in a correct manner.
Here is the stack trace we get by executing CyclicDependancyManualTest (again, without expected exception):
This stack trace shows the line numbers that cause the problem in the two classes that are in a cyclic relationship. Line number 9 of ClassTwo and line number 9 of the ClassOne point to the location inside the constructor where it tries to instantiate the other class.
Once the code is being thoroughly inspected and if none of the following (or any other code logic error) is the cause of the error:
- Incorrectly implemented recursion (i.e. with no termination condition)
- Cyclic dependency between classes
- Instantiating a class within the same class as an instance variable of that class
It would be a good idea to try and increase the stack size. Depending on the JVM installed, the default stack size could vary.
The -Xss flag can be used to increase the size of the stack, either from the project’s configuration or the command line.
5. Conclusion
In this article, we took a closer look at the StackOverflowError including how Java code can cause it and how we can diagnose and fix it.
Source code related to this article can be found over on GitHub.
Java.lang.StackOverflowError при сохранении объекта jpa
Я создаю приложение, используя JPA, JSF, EJB, Derby. На данный момент приложение все еще мало. У меня есть форма в приложении для добавления новых продуктов. При добавлении данных в db он идет гладко, пока я не перезапущу приложение или сервер. Когда я перезапускаю сервер или приложение, я получаю java.lang.StackOverflowError , я все еще могу запросить db для данных, представленных продуктом db, но создание продукта невозможно. На данный момент у меня всего 5 записей в db, но я очень обеспокоен этим случаем так рано.
Это Ejb (Getter, setter и конструкторы удалены для простоты):
это ProductController (Getter, setter и конструкторы удалены для простоты):
Категория объекта (Getters, seters, hash() и конструкторы удалены для простоты):
Product Entity (Getters, seters, hash() и конструкторы удалены для простоты):
В вашем классе Category есть список Products и в методе equals класса Category , который вы выполняете
который вызывает метод equals в классе Product , метод equals в классе Product , который выполняет
который снова вызывает метод equals на Category , и весь процесс повторяется, вызывая переполнение стека.
- Либо удалить двунаправленную зависимость.
- Исправить метод equals.
Надеюсь, что это поможет.
Я подозреваю, что круговая зависимость является основной причиной проблемы. Я думаю, что вы сопоставили Product либо в Category , либо SaleDetails , либо оба объекта. Если это так, он вызовет проблему с круглым ссылочным номером при сериализации объекта Product , в результате чего произойдет ошибка StackOverFlow .
Я думаю, у вас есть два варианта:
- Удалите отображение bi-dreictional , если его можно избежать.
- Внесите readObject() и writeObject() методы в классы Product , Category и SaleDetails и избегайте чтения/записи объектов в кругах.
Надеюсь, что это поможет.
Как сказал @Sajan. У вас есть циклическая зависимость в ваших equals().
Вам нужно изменить метод equals() в вашем классе категории, чтобы не ссылаться на список «Product» и «categoryId». Вероятно, он должен быть следующим:
В методе equals() в классе Product вам может потребоваться удалить «ProductId» и «Price».
Методы equals() и hashcode() важны, поскольку они определяют равенство объектов, когда вы используете объекты в отдельном состоянии и добавляете их в java.util.Set.
Рекомендуемая реализация заключается в использовании «свойств, которые образуют идентификатор естественного ключа» в реализациях equals() и hashcode().
Категория —
Скажем, у вас есть CategoryA с ProductA и ProductB. Не исключено, что те же ProductA и ProductB будут привязаны к другой категории, называемой CategoryB. Таким образом, они не должны быть частью реализации equals().
Продукт —
Включить «Категория» в Product.equals() зависит от того, является ли «Категория» частью идентификатора естественного ключа для Продукта. И тот факт, что вы используете список внутри категории, означает, что вы не слишком обеспокоены равенством объектов. Если вас беспокоит равенство(), я бы рекомендовал вам изменить его на Set.
Если у вас был следующий сценарий —
name — Камера | цена — $100 | категория — Электроника
name — HandyCam | Цена — $200 | Категория — Электроника
Если категория «Электроника» имеет набор из двух продуктов, как показано выше.
Если у вас был следующий пример кода —
Когда вы меняете цену камеры и добавляете ее обратно в Set, вы хотите убедиться, что набор все еще содержит только два элемента и не добавляет третий новый элемент, потому что вы изменяете существующий продукт, не добавляя новый продукт.
В приведенном выше сценарии вам нужно иметь «Категория» и «имя» в методе equals() «Product».
Кажется, что проблема в классе Category — equals делает что-то, что в свою очередь вызывает equals, создавая бесконечный цикл
Java Exception Handling – StackOverflowError
Making our way through our in-depth Java Exception Handling series, today we’ll dig into the Java StackOverflowError. As with most programming languages, the StackOverflowError in Java occurs when the application performs excessively deep recursion. However, what exactly qualifies as “excessively deep” depends on many factors.
In this article we’ll explore the StackOverflowError a bit more by first looking where it resides in the overall Java Exception Hierarchy. We’ll also look at a simple, functional code sample that will illustrate how deep recursion can be created, and what might cause a StackOverflowError in your own code. Let’s get going!
The Technical Rundown
All Java errors implement the java.lang.Throwable interface, or are extended from another inherited class therein. The full exception hierarchy of this error is:
Full Code Sample
Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.
When Should You Use It?
Before we look at what might cause a StackOverflowError in Java code, let’s first take a moment to review what a stack overflow actually is. Most applications are allocated a range of memory addresses that the application can use during execution. These addresses are stored and used as simple pointers to bytes of data (i.e. memory). This collection of addresses is known as the address space assigned to the application, and it contains a specific range of memory addresses that can be safely used by the application.
Unfortunately, at least for the foreseeable future, available memory is a finite resource. A Java application is limited to the bounds of its assigned address space . Processes like garbage collection will constantly free up memory that is no longer in use, but, by and large, there is a limited quantity of memory addresses available to any given application.
When an application attempts to use memory outside of its assigned address space a stack overflow error typically occurs. The runtime that is handling the application cannot safely allow said application to use memory that hasn’t been assigned to it, so the only logical course of action is to throw an error of some sort. In the case of Java, this is where the StackOverflowError comes in.
There are many different ways a stack overflow can occur within any given application, but one of the most common (and easily understood) is infinite recursion . This essentially means that a function or method is calling itself, over and over, ad nauseam. Different languages handle infinite recursion differently, but the Java Virtual Machine ( JVM ) handles infinite recursion by eventually throwing a StackOverflowError . To illustrate this behavior our example code is quite simple, primarily performed in the Iterator class:
As you can see, we have a few private members, along with the increment() method, which attempts a simple task: Iterate the count field, then call itself again. We also catch the potential errors (or Throwables ) that might come up from this process.
Let’s create a new instance of Iterator and start the recursive process by calling the increment() method:
Executing the few lines of code above produces the following output:
We can see that a StackOverflowError was thrown, as expected, and it took about 7,200 iterations before the error occurred, with a total processing time of about 5.2 milliseconds. This is just one test, so let’s run it a few more times and record the results:
What’s immediately interesting is that, while a StackOverflowError is thrown every time, the number of recursive iterations necessary to cause the error changes every time, but within a reasonably similar range. The reason for this difference is due to the vast quantity of different factors within the system when execution occurs. For example, the JVM I’m testing this on is Windows 10 64-bit with 16GB of memory, but if we run this application on other machines (with different JVM configurations), we might see completely different iteration counts and/or elapsed times.
The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java easily integrates with all the latest Java frameworks and platforms like Spring , Maven , log4j , Struts , Kotlin , Grails , Groovy , and many more. Plus, Airbrake-Java allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.
Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!