Что может вызвать java.lang.StackOverflowError
? Распечатка стека, которую я получаю, совсем не очень глубокая (всего 5 методов).
Ответы:
Проверьте наличие повторных вызовов методов. В основном это вызвано рекурсивным вызовом метода. Простой пример:
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Здесь System.out.println (i); будет многократно помещаться в стек при вызове testMethod.
Одним из (необязательных) аргументов JVM является размер стека. Это -Xss. Я не знаю, что такое значение по умолчанию, но если общее количество материала в стеке превышает это значение, вы получите эту ошибку.
Обычно причиной этого является бесконечная рекурсия, но если бы вы это видели, ваша трассировка стека имела бы более 5 кадров.
Попробуйте добавить аргумент -Xss (или увеличить его значение), чтобы увидеть, исчезнет ли это.
На самом деле причиной java.lang.StackOverflowError обычно является непреднамеренная рекурсия. Для меня это часто, когда я намеревался вызвать супер-метод для скрытого метода. Например, в этом случае:
public class Vehicle {
public void accelerate(float acceleration, float maxVelocity) {
// set the acceleration
}
}
public class SpaceShip extends Vehicle {
@Override
public void accelerate(float acceleration, float maxVelocity) {
// update the flux capacitor and call super.accelerate
// oops meant to call super.accelerate(acceleration, maxVelocity);
// but accidentally wrote this instead. A StackOverflow is in our future.
this.accelerate(acceleration, maxVelocity);
}
}
Во-первых, полезно знать, что происходит за кулисами, когда мы вызываем функцию. Аргументы и адрес того места, где был вызван метод, помещаются в стек (см. Http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ), чтобы вызываемый метод мог получить доступ к аргументам и чтобы при вызываемый метод завершен, выполнение может продолжаться после вызова. Но поскольку мы вызываем this.accelerate (ускорение, maxVelocity) рекурсивно (рекурсия не является произвольной, когда метод вызывает сам себя. Для получения дополнительной информации см. Http://en.wikipedia.org/wiki/Recursion_(computer_science)) мы находимся в ситуации, известной как бесконечная рекурсия, и продолжаем накапливать аргументы и адрес возврата в стеке вызовов. Поскольку размер стека вызовов конечен, в конечном итоге нам не хватает места. Нехватка места в стеке вызовов называется переполнением. Это потому, что мы пытаемся использовать больше места в стеке, чем у нас есть, и данные буквально переполняют стек. В языке программирования Java это приводит к исключению времени выполнения java.lang.StackOverflow и немедленно останавливает программу.
Приведенный выше пример несколько упрощен (хотя со мной такое случается чаще, чем я хотел бы признать). То же самое может произойти и более обходным путем, поэтому его немного сложнее отследить. Однако в целом StackOverflow обычно довольно легко разрешить, если он возникает.
Теоретически также возможно переполнение стека без рекурсии, но на практике это может показаться довольно редким событием.
java.lang.StackOverflowError
Ошибка java.lang.StackOverflowError
выдается, чтобы указать, что стек приложения был исчерпан из-за глубокой рекурсии, то есть ваша программа / сценарий рекурсии слишком глубоко.
Класс StackOverflowError
extends, VirtualMachineError
который указывает, что JVM исчерпали или исчерпали ресурсы и не может работать дальше. VirtualMachineError
, Который расширяет Error
класс используется для указания тех серьезных проблем , что приложение не должно поймать. Метод может не объявлять такие ошибки в своем throw
разделе, потому что эти ошибки являются ненормальными условиями, которые никогда не ожидались.
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);
}
}
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)
Когда вызов функции вызывается приложением Java, в стеке вызовов выделяется кадр стека . stack frame
Содержит параметры, вызываемый метод его локальных параметров, а также обратный адрес метода. Адрес возврата обозначает точку выполнения, с которой выполнение программы должно продолжаться после возврата из вызванного метода. Если нет места для нового кадра стека, то StackOverflowError
виртуальная машина Java (JVM) выбрасывает его.
Наиболее частым случаем, который может исчерпать стек Java-приложения, является рекурсия. В рекурсии метод вызывает себя во время выполнения. Recursion
один из самых мощных методов программирования общего назначения, но его следует использовать с осторожностью, StackOverflowError
чтобы избежать ошибок.
Когда вызов функции вызывается приложением Java, в стеке вызовов выделяется кадр стека. Кадр стека содержит параметры вызываемого метода, его локальные параметры и адрес возврата метода.
Адрес возврата обозначает точку выполнения, с которой выполнение программы должно продолжаться после возврата из вызванного метода. Если нет никакого пространства для нового кадра стека пор StackOverflowError выбрасывается в виртуальной машине Java (JVM) .
Наиболее частым случаем, который может исчерпать стек Java-приложения, является рекурсия.
Пожалуйста, посмотрите
Решение для пользователей Hibernate при парсинге данных:
У меня была эта ошибка, потому что я анализировал список объектов, сопоставленных с обеих сторон, @OneToMany
и @ManyToOne
json с помощью jackson, что вызвало бесконечный цикл.
Если вы находитесь в такой же ситуации , вы можете решить эту проблему с помощью @JsonManagedReference
и @JsonBackReference
аннотаций.
Определения из API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
Аннотация, используемая для обозначения того, что аннотированное свойство является частью двусторонней связи между полями; и что его роль - «родительская» (или «прямая») ссылка. Тип значения (класс) свойства должен иметь единственное совместимое свойство, аннотированное JsonBackReference. Связывание обрабатывается таким образом, что свойство, аннотированное этой аннотацией, обрабатывается нормально (обычно сериализуется, без специальной обработки для десериализации); это соответствующая обратная ссылка, требующая особой обработки
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Аннотация используется, чтобы указать, что связанное свойство является частью двусторонней связи между полями; и что его роль - «дочерняя» (или «обратная») ссылка. Тип значения свойства должен быть bean-компонентом: он не может быть коллекцией, картой, массивом или перечислением. Связывание обрабатывается таким образом, что свойство, помеченное этой аннотацией, не сериализуется; и во время десериализации его значение устанавливается равным экземпляру, имеющему «управляемую» (прямую) ссылку.
Пример:
Owner.java:
@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;
Car.java:
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
Другое решение - использовать, @JsonIgnore
который просто установит значение null в поле.
Я создал программу с hibernate, в которой я создал два класса POJO, оба с объектами друг друга в качестве членов данных. Когда в основном методе я пытался сохранить их в базе данных, я также получил эту ошибку.
Это происходит потому, что оба класса ссылаются друг на друга, следовательно, создается цикл, вызывающий эту ошибку.
Итак, проверьте, существуют ли такие отношения в вашей программе.
Исключения переполнения стека могут возникать, когда стек потока продолжает увеличиваться в размере до достижения максимального предела.
Настройка параметров размера стека (Xss и Xmso) ...
Я предлагаю вам увидеть эту ссылку: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Существует много возможных причин StackOverflowError, как вы можете видеть по ссылке ....
В моем случае у меня есть два занятия. Во втором упражнении я забыл поставить super на метод onCreate.
super.onCreate(savedInstanceState);
StackOverflowError
, я не думаю, что он отвечает на вопрос. Я думаю, что правильный ответ должен либо перечислить другие способы получить это исключение, кроме использования слишком большой рекурсии, либо сказать, что определенно нет другого способа получить такое исключение, кроме как выбросить его вручную.