Что вызывает java.lang.StackOverflowError

Ответы:

60

Проверьте наличие повторных вызовов методов. В основном это вызвано рекурсивным вызовом метода. Простой пример:

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.

Тота Шринатх
источник
1
Я думаю, вы правы. Но каково это решение. Поскольку мы создаем метод отвода, это означает, что нам это нужно. Мы не хотим менять метод. Так как же разобраться с этой ошибкой?
Аджай Шарма
1
или вы попадаете в бесконечный цикл!
yalematta
@yalematta, любой рекурсивный метод должен иметь условие выхода. Поэтому проверьте, правильно ли реализован ваш рекурсивный метод и завершается ли он в зависимости от некоторых условий.
Аяз Алифов
@AjaySharma Нам нужно спроектировать нашу систему так, чтобы она соответствовала доступным границам памяти, которые мы назначили JVM. Если система ведет себя неуклюже со следующей ошибкой, нам нужно проверить нашу базу кода.
Thota Srinath
23

Одним из (необязательных) аргументов JVM является размер стека. Это -Xss. Я не знаю, что такое значение по умолчанию, но если общее количество материала в стеке превышает это значение, вы получите эту ошибку.

Обычно причиной этого является бесконечная рекурсия, но если бы вы это видели, ваша трассировка стека имела бы более 5 кадров.

Попробуйте добавить аргумент -Xss (или увеличить его значение), чтобы увидеть, исчезнет ли это.

nsayer
источник
10

На самом деле причиной 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 обычно довольно легко разрешить, если он возникает.

Теоретически также возможно переполнение стека без рекурсии, но на практике это может показаться довольно редким событием.

Птуинсон
источник
8

Что такое java.lang.StackOverflowError

Ошибка java.lang.StackOverflowErrorвыдается, чтобы указать, что стек приложения был исчерпан из-за глубокой рекурсии, то есть ваша программа / сценарий рекурсии слишком глубоко.

Детали

Класс StackOverflowErrorextends, 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чтобы избежать ошибок.

Ссылки

ДебанджанБ
источник
4

Когда вызов функции вызывается приложением Java, в стеке вызовов выделяется кадр стека. Кадр стека содержит параметры вызываемого метода, его локальные параметры и адрес возврата метода.

Адрес возврата обозначает точку выполнения, с которой выполнение программы должно продолжаться после возврата из вызванного метода. Если нет никакого пространства для нового кадра стека пор StackOverflowError выбрасывается в виртуальной машине Java (JVM) .

Наиболее частым случаем, который может исчерпать стек Java-приложения, является рекурсия.

Пожалуйста, посмотрите

Как решить StackOverflowError

IntelliJ Amiya
источник
3

Решение для пользователей Hibernate при парсинге данных:

У меня была эта ошибка, потому что я анализировал список объектов, сопоставленных с обеих сторон, @OneToManyи @ManyToOnejson с помощью 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 в поле.

Эмерика
источник
2

Я создал программу с hibernate, в которой я создал два класса POJO, оба с объектами друг друга в качестве членов данных. Когда в основном методе я пытался сохранить их в базе данных, я также получил эту ошибку.

Это происходит потому, что оба класса ссылаются друг на друга, следовательно, создается цикл, вызывающий эту ошибку.

Итак, проверьте, существуют ли такие отношения в вашей программе.

Сингх
источник
1

Исключения переполнения стека могут возникать, когда стек потока продолжает увеличиваться в размере до достижения максимального предела.

Настройка параметров размера стека (Xss и Xmso) ...

Я предлагаю вам увидеть эту ссылку: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Существует много возможных причин StackOverflowError, как вы можете видеть по ссылке ....

Марзи Гадириния
источник
Ответы только по ссылкам обычно неприемлемы; ссылки разрываются, что полностью аннулирует ответ. Укажите контекст, код и объяснение ответа вместо ссылки.
Джей
0

В моем случае у меня есть два занятия. Во втором упражнении я забыл поставить super на метод onCreate.

super.onCreate(savedInstanceState);
Юлз Этналоб
источник
Даже если это возможный способ поднять a StackOverflowError, я не думаю, что он отвечает на вопрос. Я думаю, что правильный ответ должен либо перечислить другие способы получить это исключение, кроме использования слишком большой рекурсии, либо сказать, что определенно нет другого способа получить такое исключение, кроме как выбросить его вручную.
JojOatXGME