Що викликає java.lang.StackOverflowError


Відповіді:


59

Перевірте наявність рекусивних викликів методів. В основному це викликається, коли існує рекурсивний виклик методу. Простий приклад

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 (або збільшити значення одного), щоб побачити, чи це не зникне.


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


2

Я створив програму зі сплячим режимом, в якій створив два класи POJO, обидва з об’єктом один одного як члени даних. Коли в основному методі я намагався зберегти їх у базі даних, я також отримав цю помилку.

Це відбувається тому, що обидва класи посилаються один на одного, отже, створюється цикл, який спричиняє цю помилку.

Отже, перевірте, чи існують такі стосунки у вашій програмі.


2

Рішення для користувачів 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 ):

    Анотація, що використовується для позначення того, що пов'язане властивість є частиною двостороннього зв'язку між полями; і що його роль полягає в "дочірньому" (або "зворотному") посиланні. Тип значення властивості повинен бути компонентом: він не може бути колекцією, картою, масивом або переліком. Зв'язок обробляється таким чином, що властивість, коментована цією анотацією, не є серіалізованою; і під час десеріалізації його значення встановлюється як екземпляр, який має посилання "керований" (прямий).

Приклад:

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 для поля.


1

Винятки із переповнення стека можуть виникати, коли стек ниток продовжує збільшуватися в розмірі до досягнення максимального обмеження.

Налаштування параметрів розмірів стеку (Xss та Xmso) ...

Я пропоную вам переглянути це посилання: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Існує багато можливих причин StackOverflowError, як ви можете бачити за посиланням ....


Відповіді лише на посилання, як правило, не прийнятні; посилання розриваються, що повністю зневажає відповідь. Будь ласка, надайте трохи контексту, коду та пояснення відповіді, а не лише посилання.
Джей

0

У моєму випадку я маю дві діяльності. Під час другого заходу я забув поставити супер на метод onCreate.

super.onCreate(savedInstanceState);

Навіть якщо це можливий спосіб підняти StackOverflowError, я не думаю, що він відповідає на питання. Я думаю, що правильна відповідь повинна перерахувати інші способи отримати цей виняток, ніж використання занадто великої кількості рекурсії, або сказати, що точно не існує іншого способу отримати такий виняток, крім кидання його вручну.
JojOatXGME
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.