web-dev-qa-db-fra.com

Pourquoi est-il possible de récupérer une erreur StackOverflowError?

Je suis surpris de voir comment il est possible de continuer l'exécution même après qu'un StackOverflowError se soit produit en Java.

Je sais que StackOverflowError est une sous-classe de la classe Error . La classe Error est considérée comme "une sous-classe de Throwable qui indique des problèmes graves qu'une application raisonnable ne devrait pas tenter de détecter."

Cela ressemble plus à une recommandation qu'à une règle, affirmant que capturer une erreur comme une erreur 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 lancé, la pile devrait être tellement pleine qu'il n'y a plus de place pour appeler une autre fonction. Le bloc de traitement des erreurs fonctionne-t-il dans une pile différente ou que se passe-t-il ici?

98
user3370796

Lorsque la pile déborde et que StackOverflowError est lancé, la gestion des exceptions habituelles décompose la pile. Dérouler la pile signifie:

  • abandonner l'exécution de la fonction actuellement active
  • efface son cadre de pile, continue avec la fonction appelante
  • abandonner l'exécution de l'appelant
  • efface son cadre de pile, continue avec la fonction appelante
  • etc...

... jusqu'à ce que l'exception soit capturée. C’est normal (en fait, nécessaire) et indépendant de l’exception et de la raison. Puisque vous interceptez l'exception en dehors du premier appel à foo(), les milliers de trames de pile foo qui ont rempli la pile ont toutes été déroulées et la plus grande partie de la pile peut être réutilisée.

117
user395760

Lorsque StackOverflowError est renvoyé, la pile est pleine. Cependant, quand il est attrapé , tous ces appels foo ont été sortis de la pile. bar peut fonctionner normalement car la pile ne déborde plus avec foos. (Notez que je ne pense pas que JLS vous garantisse que vous pouvez récupérer d'un débordement de pile comme celui-ci.)

23
user2357112

Lorsque le StackOverFlow se produit, la JVM descendra à la capture, libérant la pile.

Dans votre exemple, il récupère tous les objets empilés.

12

Parce que la pile ne déborde pas réellement. Un meilleur nom pourrait être AttemptToOverflowStack. En gros, cela signifie que la dernière tentative d'ajustement du cadre de la pile est une erreur car il ne reste plus assez d'espace libre sur la pile. La pile pourrait en fait avoir beaucoup d’espace disponible, mais pas assez d’espace. Ainsi, quelle que soit l'opération qui aurait dépendu du succès de l'appel (typiquement une invocation de méthode), elle n'est jamais exécutée et il ne reste plus que le programme pour gérer ce fait. Ce qui signifie que ce n'est pas vraiment différent de toute autre exception. En fait, vous pouvez intercepter l'exception dans la fonction qui effectue l'appel.

8
jmoreno