Wat veroorzaakt een java.lang.stackoverflowerror

Wat kan een java.lang.StackOverflowErrorveroorzaken? De stapelafdruk die ik krijg is helemaal niet erg diep (slechts 5 methoden).


1, Autoriteit 100%

Controleer op alle reclusieve oproepen voor methoden. Vooral wordt het veroorzaakt wanneer er een recursieve oproep is voor een methode. Een eenvoudig voorbeeld is

public static void main(String... args) {
    Main main = new Main();
    main.testMethod(1);
}
public void testMethod(int i) {
    testMethod(i);
    System.out.println(i);
}

HIER HET SYSTEM.OUT.PRINTLN (I); wordt herhaaldelijk geduwd om te stapelen wanneer de testmethod wordt genoemd.


2, Autoriteit 36%

Een van de (optionele) argumenten voor de JVM is de stapelgrootte. Het is -xss. Ik weet niet wat de standaardwaarde is, maar als de totale hoeveelheid dingen op de stapel deze waarde overschrijdt, krijgt u die fout.

Over het algemeen is oneindige recursie de oorzaak hiervan, maar als u erop zag, zou uw stapelspoor meer dan 5 frames hebben.

Probeer het toevoegen van een -xss-argument (of het vergroten van de waarde van één) om te zien of dit weggaat.


3, Autoriteit 17%

Wat daadwerkelijk een Java.lang veroorzaakt.stackoveroverflowerror is typisch onbedoelde recursie. Voor mij is het vaak wanneer ik van plan was om een ​​supermethode voor de overgeege methode te bellen. Zoals in dit geval:

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); 
    }
}

Ten eerste is het handig om te weten wat er achter de schermen gebeurt als we een functie aanroepen. De argumenten en het adres waar de methode werd aangeroepen, worden op de stapel geduwd (zie http://en.wikipedia .org/wiki/Stack_(abstract_data_type)#Runtime_memory_management) zodat de aangeroepen methode toegang heeft tot de argumenten en zodat wanneer de aangeroepen methode is voltooid, de uitvoering kan worden voortgezet na de aanroep. Maar aangezien we this.accelerate(acceleration, maxVelocity) recursief aanroepen (recursie is losjes wanneer een methode zichzelf aanroept. Voor meer info zie http://en.wikipedia.org/wiki/Recursion_(computer_science)) we bevinden ons in een situatie die bekend staat als oneindige recursie en we blijven de argumenten en het retouradres op de call-stack stapelen. Omdat de call-stack eindig is, hebben we uiteindelijk geen ruimte meer. Het opraken van ruimte op de call-stack staat bekend als overloop. Dit komt omdat we proberen meer stapelruimte te gebruiken dan we hebben en de gegevens letterlijk over de stapel lopen. In de programmeertaal Java resulteert dit in de runtime-uitzondering java.lang.StackOverflow en zal het programma onmiddellijk stoppen.

Het bovenstaande voorbeeld is enigszins vereenvoudigd (hoewel het mij meer overkomt dan ik zou willen toegeven.) Hetzelfde kan op een meer omslachtige manier gebeuren, waardoor het een beetje moeilijker op te sporen is. Over het algemeen is de StackOverflow echter meestal vrij eenvoudig op te lossen, zodra deze zich voordoet.

In theorie is het ook mogelijk om een ​​stapeloverloop zonder recursie te hebben, maar in de praktijk lijkt het een vrij zeldzaam evenement te zijn.


4, Autoriteit 17%

Wat is java.lang.StackOverflowError

De fout java.lang.StackOverflowErrorwordt gegooid om aan te geven dat de stapel van de toepassing is uitgeput, vanwege de diepe recursie, dwz uw programma / script te diep.

Details

De StackOverflowErrorverlengt VirtualMachineErrorClass die aangeeft dat de JVM is geweest of geen middelen heb gehad en kan niet verder werken. De VirtualMachineError, die de Errorwordt gebruikt, wordt gebruikt om die serieuze problemen aan te geven die een aanvraag niet mag vangen. Een methode mag dergelijke fouten niet declareren in zijn throwclausule omdat deze fouten abnormale voorwaarden zijn die nooit verwacht te komen.

Een voorbeeld

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-uitvoer

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)

Uitleg

Als een functieaanroep wordt aangeroepen door een Java-toepassing, wordt een stackframetoegewezen aan de aanroepstack. Het stack framebevat de parameters van de aangeroepen methode, de lokale parameters en het retouradres van de methode. Het retouradres geeft het uitvoeringspunt aan van waaruit de uitvoering van het programma zal doorgaan nadat de aangeroepen methode terugkeert. Als er geen ruimte is voor een nieuw stackframe, wordt de StackOverflowErrorgegenereerd door de Java Virtual Machine (JVM).

Het meest voorkomende geval dat de stack van een Java-toepassing kan uitputten, is recursie. Bij recursie roept een methode zichzelf aan tijdens de uitvoering ervan. Recursioneen van de krachtigste programmeertechnieken voor algemeen gebruik, maar moet met de nodige voorzichtigheid worden gebruikt om de StackOverflowErrorte vermijden.

Referenties


Antwoord 5, autoriteit 6%

Wanneer een functieaanroep wordt aangeroepen door een Java-toepassing, wordt een stapelframe toegewezen aan de aanroepstack. Het stapelframe bevat de parameters van de aangeroepen methode, de lokale parameters en het retouradres van de methode.

Het retouradres geeft het uitvoeringspunt aan van waaruit de uitvoering van het programma zal doorgaan nadat de aangeroepen methode terugkeert. Als er geen ruimte is voor een nieuw stapelframe, wordt de StackOverflowErrorwordt gegenereerd door de Java Virtual Machine (JVM).

Het meest voorkomende geval dat de stack van een Java-toepassing kan uitputten, is recursie.

Kijk eens

Hoe StackOverflowError op te lossen


Antwoord 6, autoriteit 6%

Oplossing voor Hibernate-gebruikers bij het ontleden van gegevens:

Ik kreeg deze fout omdat ik een lijst met objecten aan het ontleden was die aan beide kanten @OneToManyen @ManyToOnewaren toegewezen aan json met behulp van jackson, wat een oneindige lus veroorzaakte.

p>

Als u zich in dezelfde situatie bevindt, kunt u dit oplossen door de annotaties @JsonManagedReferenceen @JsonBackReferencete gebruiken.

Definities van API:

  • JsonManagedReference (https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html) :

    Annotatie die wordt gebruikt om aan te geven dat de geannoteerde eigenschap deel uitmaakt van tweerichtingsverkeer
    koppeling tussen velden; en dat zijn rol “ouder” (of “forward”) is
    koppeling. Waardetype (klasse) van eigenschap moet een enkele compatibele hebben
    eigenschap geannoteerd met JsonBackReference. Koppeling wordt zo behandeld:
    dat de eigenschap die is geannoteerd met deze annotatie normaal wordt behandeld
    (normaal geserialiseerd, geen speciale behandeling voor deserialisatie); het is
    de bijpassende back-referentie die een speciale behandeling vereist

  • JsonBackReference: (https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html):

    Annotatie die wordt gebruikt om aan te geven dat de bijbehorende eigenschap deel uitmaakt van
    tweerichtingskoppeling tussen velden; en dat zijn rol is “kind” (of
    “terug”) link. Waardetype van de eigenschap moet een boon zijn: dat kan niet zijn
    een verzameling, kaart, array of opsomming. Koppeling wordt zodanig behandeld dat:
    de eigenschap die met deze annotatie is geannoteerd, is niet geserialiseerd; en
    tijdens deserialisatie wordt de waarde ingesteld op instantie met de
    “beheerde” (doorsturen) link.

Voorbeeld:

Eigenaar.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;

Een andere oplossing is om @JsonIgnorete gebruiken die net null in het veld zal instellen.


7, Autoriteit 3%

Ik heb een programma gemaakt met een overwinning, waarin ik twee Pojo-klassen heb gemaakt, zowel met een doel van elkaar als dataseden. Wanneer ik in de hoofdmethode heb geprobeerd ze in de database te redden, kreeg ik ook deze fout.

Dit gebeurt omdat beide klassen elkaar verwijzen, dus het maken van een lus die deze fout veroorzaakt.

Controleer dus of dergelijke relaties in uw programma bestaan.


8, Autoriteit 2%

Stack overloopuitzonderingen kunnen optreden wanneer een draadstapel blijft groeien in omvang tot het bereiken van de maximale limiet.

Instellen van de opties voor stapelmaten (XSS en XMSO) …

Ik stel voor dat u deze link ziet:
http://www-01.ibm.com/support/docview. WSS? UID = SWG21162896
Er zijn veel mogelijke oorzaken tot een StackoverFlowerror, zoals je kunt zien in de link ….


9

Ik had hetzelfde probleem

rol.java

@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY,cascade = CascadeType.ALL)
 Set<BusinessUnitMaster> businessUnits =new HashSet<>();

businessUnitmaster.java

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
        name = "BusinessUnitRoles",
        joinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "record_id")},
        inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "record_id")}
)
private Set<Role> roles=new HashSet<>();

het probleem is dat wanneer u BusinessUnitMaster en Role maakt
je moet het object voor beide kanten opslaan
voor RoleService.java

roleRepository.save(role);

voor BusinessUnitMasterService.java

businessUnitMasterRepository.save(businessUnitMaster);

Antwoord 10

In mijn geval toStringde uitzondering in de entiteitenklasse veroorzaken, controleer uw systeemlogboeken, dit zal u helpen de uitzondering op te lossen

Other episodes