Je suis surpris de voir comment il est possible de continuer l'exécution même après une StackOverflowError
survenue en Java.
Je sais que StackOverflowError
c'est une sous-classe de la classe Error. La classe Error est décrite comme «une sous-classe de Throwable qui indique des problèmes graves qu'une application raisonnable ne devrait pas essayer d'attraper».
Cela ressemble plus à une recommandation qu'à une règle, sous-tendant qu'attraper une erreur comme un StackOverflowError est en fait autorisé et qu'il appartient au programmeur de ne pas le faire. Et voyez, j'ai testé ce code et il se termine normalement.
public class Test
{
public static void main(String[] args)
{
try {
foo();
} catch (StackOverflowError e) {
bar();
}
System.out.println("normal termination");
}
private static void foo() {
System.out.println("foo");
foo();
}
private static void bar() {
System.out.println("bar");
}
}
Comment se peut-il? Je pense qu'au moment où StackOverflowError est jeté, la pile devrait être si pleine qu'il n'y a pas de place pour appeler une autre fonction. Le bloc de gestion des erreurs s'exécute-t-il dans une pile différente ou que se passe-t-il ici?
la source
Réponses:
Lorsque la pile déborde et
StackOverflowError
est levée, la gestion habituelle des exceptions déroule la pile. Dérouler la pile signifie:... jusqu'à ce que l'exception soit interceptée. Ceci est normal (en fait, nécessaire) et indépendamment de l'exception lancée et pourquoi. Puisque vous attrapez l'exception en dehors du premier appel à
foo()
, les milliers defoo
cadres de pile qui remplissaient la pile ont tous été déroulés et la majeure partie de la pile peut être réutilisée.la source
foo
terminé avec un état indéfini, de sorte que tout objet qu'il a pu toucher doit être supposé être brisé. Comme vous ne savez pas dans quelle fonction le débordement de pile s'est produit, seulement qu'il doit être un descendant dutry
bloc qui l'a attrapé, tout objet pouvant être modifié par n'importe quelle méthode accessible à partir de là est maintenant suspect. Il n'est généralement pas utile de découvrir ce qui s'est passé et d'essayer de le réparer.Error
s ne peut pas être anticipé même lors de l'écriture de code de sécurité d'exception.Error
art. L'OP ne demande que surStackOverflowError
, et il demande une chose spécifique sur la gestion de cette erreur: comment un appel de méthode peut-il ne pas échouer lorsque cette erreur est interceptée.Lorsque le StackOverflowError est levé, la pile est pleine. Cependant, lorsqu'il est intercepté , tous ces
foo
appels ont été extraits de la pile.bar
peut fonctionner normalement car la pile ne déborde plus defoo
s. (Notez que je ne pense pas que le JLS garantit que vous pouvez récupérer d'un débordement de pile comme celui-ci.)la source
Lorsque le StackOverFlow se produit, la JVM apparaîtra vers le crochet, libérant la pile.
Dans votre exemple, il récupère tous les toto empilés.
la source
Parce que la pile ne déborde pas réellement. Un meilleur nom pourrait être AttemptToOverflowStack. Fondamentalement, cela signifie que la dernière tentative d'ajustement du cadre de la pile est erronée car il n'y a pas assez d'espace libre sur la pile. La pile pourrait en fait avoir beaucoup d'espace, mais pas assez d'espace. Ainsi, quelle que soit l'opération qui aurait dépendu de la réussite de l'appel (généralement une invocation de méthode), elle n'est jamais exécutée et il ne reste plus qu'au programme pour gérer ce fait. Ce qui signifie que ce n'est vraiment pas différent de toute autre exception. En fait, vous pouvez intercepter l'exception dans la fonction qui effectue l'appel.
la source
Comme cela a déjà été répondu , il est possible d'exécuter du code, et en particulier d'appeler des fonctions, après avoir attrapé un
StackOverflowError
car la procédure normale de gestion des exceptions de la JVM déroule la pile entrethrow
lescatch
points et, libérant de l'espace de pile à utiliser. Et votre expérience confirme que c'est le cas.Cependant, ce n'est pas tout à fait la même chose que de dire qu'il est, en général, possible de récupérer d'un fichier
StackOverflowError
.Un
StackOverflowError
IS-AVirtualMachineError
, qui IS-ANError
. Comme vous le faites remarquer, Java fournit quelques conseils vagues pourError
:et vous, raisonnablement, concluez que cela devrait ressembler à attraper un
Error
pourrait être OK dans certaines circonstances. Notez que la réalisation d'une expérience ne démontre pas que quelque chose est, en général, sûr à faire. Seules les règles du langage Java et les spécifications des classes que vous utilisez peuvent le faire. AVirtualMachineError
est une classe spéciale d'exception, car la spécification du langage Java et la spécification de la machine virtuelle Java fournissent des informations sur la sémantique de cette exception. En particulier, ce dernier dit :...
Le problème crucial est que vous «ne pouvez pas prédire» où et quand un
StackOverflowError
sera lancé. Il n'y a aucune garantie sur l'endroit où il ne sera pas lancé. Vous ne pouvez pas vous fier à ce qu'il soit lancé à l' entrée d'une méthode, par exemple. Il peut être jeté à un point dans une méthode.Cette imprévisibilité est potentiellement désastreuse. Comme elle peut être lancée dans une méthode, elle pourrait être lancée à mi-chemin d'une séquence d'opérations que la classe considère comme une opération "atomique", laissant l'objet dans un état partiellement modifié et incohérent. Avec l'objet dans un état incohérent, toute tentative d'utilisation de cet objet peut entraîner un comportement erroné. Dans tous les cas pratiques, vous ne pouvez pas savoir quel objet est dans un état incohérent, vous devez donc supposer qu'aucun objet n'est digne de confiance. Toute opération de récupération ou tentative de poursuite après que l'exception est interceptée peut donc avoir un comportement erroné. La seule chose sûre à faire est donc de ne pas attraper un
StackOverflowError
, mais plutôt pour permettre au programme de se terminer. (En pratique, vous pouvez essayer de faire une journalisation des erreurs pour aider au dépannage, mais vous ne pouvez pas compter sur cette journalisation fonctionnant correctement). Autrement dit, vous ne pouvez pas récupérer de manière fiable à partir d'un fichierStackOverflowError
.la source