Qu'est-ce qui peut causer un java.lang.StackOverflowError
? L'impression de pile que j'obtiens n'est pas du tout très profonde (seulement 5 méthodes).
Réponses:
Vérifiez tous les appels récusifs de méthodes. Cela est principalement dû à un appel récursif pour une méthode. Un exemple simple est
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Ici, le System.out.println (i); sera poussé à plusieurs reprises dans la pile lorsque le testMethod est appelé.
L'un des arguments (facultatifs) de la JVM est la taille de la pile. C'est -Xss. Je ne sais pas quelle est la valeur par défaut, mais si la quantité totale de choses sur la pile dépasse cette valeur, vous obtiendrez cette erreur.
Généralement, la récursivité infinie en est la cause, mais si vous voyiez cela, votre trace de pile aurait plus de 5 images.
Essayez d'ajouter un argument -Xss (ou d'augmenter la valeur d'un) pour voir si cela disparaît.
Ce qui cause réellement une erreur java.lang.StackOverflowError est généralement une récursion involontaire. Pour moi, c'est souvent lorsque j'ai eu l'intention d'appeler une super méthode pour la méthode surchargée. Comme dans ce cas:
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);
}
}
Tout d'abord, il est utile de savoir ce qui se passe dans les coulisses lorsque nous appelons une fonction. Les arguments et l'adresse de l'endroit où la méthode a été appelée sont poussés sur la pile (voir http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ) afin que la méthode appelée puisse accéder aux arguments et ainsi lorsque la méthode appelée est terminée, l'exécution peut se poursuivre après l'appel. Mais puisque nous appelons this.accelerate (accélération, maxVelocity) de manière récursive (la récursivité est vaguement quand une méthode s'appelle elle-même. Pour plus d'informations, voir http://en.wikipedia.org/wiki/Recursion_(computer_science)) nous sommes dans une situation connue sous le nom de récursivité infinie et nous continuons à empiler les arguments et l'adresse de retour sur la pile d'appels. Puisque la pile d'appels est de taille finie, nous finissons par manquer d'espace. Le manque d'espace sur la pile d'appels est appelé débordement. En effet, nous essayons d'utiliser plus d'espace de pile que nous n'en avons et les données débordent littéralement de la pile. Dans le langage de programmation Java, cela entraîne l'exception d'exécution java.lang.StackOverflow et arrêtera immédiatement le programme.
L'exemple ci-dessus est quelque peu simplifié (bien que cela m'arrive plus que je ne voudrais l'admettre.) La même chose peut se produire de manière plus circulaire, ce qui le rend un peu plus difficile à retrouver. Cependant, en général, le StackOverflow est généralement assez facile à résoudre, une fois qu'il se produit.
En théorie, il est également possible d'avoir un débordement de pile sans récursivité, mais en pratique, cela apparaîtrait comme un événement assez rare.
java.lang.StackOverflowError
L'erreur java.lang.StackOverflowError
est lancée pour indiquer que la pile de l'application a été épuisée, en raison d'une récursion profonde, c'est-à-dire que votre programme / script récursent trop profondément.
La classe StackOverflowError
extend VirtualMachineError
qui indique que la JVM a été ou a manqué de ressources et ne peut plus fonctionner. Le VirtualMachineError
qui étend la Error
classe est utilisé pour indiquer les problèmes graves qu'une application ne doit pas détecter. Une méthode peut ne pas déclarer de telles erreurs dans sa throw
clause car ces erreurs sont des conditions anormales auxquelles on ne s'attendait jamais.
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)
Lorsqu'un appel de fonction est appelé par une application Java, un cadre de pile est alloué sur la pile d'appels . Le stack frame
contient les paramètres de la méthode appelée, ses paramètres locaux et l'adresse de retour de la méthode. L'adresse de retour désigne le point d'exécution à partir duquel l'exécution du programme doit se poursuivre après le retour de la méthode invoquée. S'il n'y a pas d'espace pour un nouveau cadre de pile, le StackOverflowError
est alors lancé par la machine virtuelle Java (JVM).
Le cas le plus courant qui peut épuiser la pile d'une application Java est la récursivité. En récursivité, une méthode s'invoque lors de son exécution. Recursion
l'une des techniques de programmation polyvalentes les plus puissantes, mais doit être utilisée avec prudence, afin d' StackOverflowError
éviter le.
Lorsqu'un appel de fonction est appelé par une application Java, un cadre de pile est alloué sur la pile d'appels. Le cadre de pile contient les paramètres de la méthode appelée, ses paramètres locaux et l'adresse de retour de la méthode.
L'adresse de retour désigne le point d'exécution à partir duquel l'exécution du programme doit se poursuivre après le retour de la méthode invoquée. S'il n'y a pas d'espace pour un nouveau cadre de pile, l' erreur StackOverflowError est renvoyée par la machine virtuelle Java (JVM) .
Le cas le plus courant qui peut épuiser la pile d'une application Java est la récursivité.
Jetez un coup d'oeil s'il vous plait
Solution pour les utilisateurs d'Hibernate lors de l'analyse des données:
J'ai eu cette erreur parce que j'analysais une liste d'objets mappés des deux côtés @OneToMany
et @ManyToOne
à json en utilisant jackson, ce qui a provoqué une boucle infinie.
Si vous êtes dans la même situation, vous pouvez résoudre ce problème en utilisant @JsonManagedReference
et des @JsonBackReference
annotations.
Définitions de l'API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
Annotation utilisée pour indiquer que la propriété annotée fait partie d'un lien bidirectionnel entre les champs; et que son rôle est le lien «parent» (ou «avant»). Le type de valeur (classe) de la propriété doit avoir une seule propriété compatible annotée avec JsonBackReference. La liaison est gérée de telle sorte que la propriété annotée avec cette annotation soit gérée normalement (sérialisée normalement, pas de traitement spécial pour la désérialisation); c'est la référence arrière correspondante qui nécessite un traitement spécial
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Annotation utilisée pour indiquer que la propriété associée fait partie d'un lien bidirectionnel entre les champs; et que son rôle est le lien "enfant" (ou "retour"). Le type de valeur de la propriété doit être un bean: il ne peut pas s'agir d'une collection, d'une map, d'un tableau ou d'une énumération. La liaison est gérée de telle sorte que la propriété annotée avec cette annotation ne soit pas sérialisée; et pendant la désérialisation, sa valeur est définie sur l'instance qui a le lien «géré» (avant).
Exemple:
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;
Une autre solution consiste à utiliser @JsonIgnore
ce qui mettra simplement null dans le champ.
J'ai créé un programme avec hibernate, dans lequel j'ai créé deux classes POJO, toutes deux avec un objet l'une de l'autre en tant que données membres. Lorsque dans la méthode principale, j'ai essayé de les enregistrer dans la base de données, j'ai également eu cette erreur.
Cela se produit parce que les deux classes se réfèrent l'une à l'autre, créant ainsi une boucle qui provoque cette erreur.
Alors, vérifiez si un tel type de relations existe dans votre programme.
Des exceptions de dépassement de capacité de pile peuvent se produire lorsqu'une pile de threads continue de croître en taille jusqu'à atteindre la limite maximale.
Réglage des options des tailles de pile (Xss et Xmso) ...
Je vous suggère de voir ce lien: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Il existe de nombreuses causes possibles à une StackOverflowError, comme vous pouvez le voir dans le lien ....
Dans mon cas, j'ai deux activités. Dans la deuxième activité, j'ai oublié de mettre super sur la méthode onCreate.
super.onCreate(savedInstanceState);
StackOverflowError
, je ne pense pas qu'il réponde à la question. Je pense qu'une bonne réponse devrait soit énumérer d'autres moyens d'obtenir cette exception que d'utiliser trop de récursivité, soit dire qu'il n'y a certainement pas d'autre moyen d'obtenir une telle exception que de la lancer manuellement.