StackOverflowError lors d’un appel récursif

La question est ssortingctement théorique mais je n’ai pas trouvé de réponse. Considérez ce programme court:

public class SBtst { int i = 0; public static void main(Ssortingng[] args) { new SBtst().rec(); } public void rec() { System.out.println("rec is called "+i++); try { rec(); } catch (StackOverflowError soe) { System.out.println("completed "+soe.getStackTrace().length); } } } 

Après exécution, je reçois une sortie semblable à:

 rec is called 10472 rec is called 10473 rec is called 10474Recursion completed 1024 

Les questions sont:

  1. Pourquoi println () n’a-t-il pas complété la nouvelle ligne car, si je comprends bien, une erreur doit être générée lors de l’exécution du prochain appel rec () et elle est APRES terminée. Println () est terminé.

  2. Pourquoi n’ai-je que 1024 éléments dans le tableau stackTrace mais que i est égal à 10474? Cela signifie-t-il que tous les appels ne figurent pas dans la trace de la stack?

Pourquoi l’exception est-elle apparemment levée de l’intérieur de println?

Pourquoi println () n’a-t-il pas complété une nouvelle ligne? Si j’ai bien compris, l’exception devrait être levée lors de l’exécution du prochain appel rec (), mais ce serait après la fin de println ().

Votre compréhension n’est pas tout à fait correcte. À un moment donné, la stack ressemble à ceci:

 … rec() rec() rec() println() 

Println consum également des ressources (voir la réponse de mattingly890 ), et rien n’empêche de penser que vous ne pouvez pas atteindre la limite à ce stade.

Pourquoi la trace de la stack contient-elle moins d’images que ce qui a été réellement utilisé?

Pourquoi n’ai-je que 1024 éléments dans la trace de la stack, même si au moins 10474 ont été utilisés? Cela signifie-t-il que tous les appels ne figurent pas dans la trace de la stack?

Consultez la documentation de getStackTrace () :

Fournit un access par programme aux informations de trace de stack imprimées par printStackTrace (). Retourne un tableau d’éléments de trace de stack, chacun représentant un cadre de stack. L’élément zeroth du tableau (en supposant que la longueur du tableau est non nulle) représente le haut de la stack, qui correspond à la dernière invocation de méthode de la séquence. En règle générale, c’est le moment où ce jetable a été créé et jeté. Le dernier élément du tableau (en supposant que la longueur du tableau est non nulle) représente le bas de la stack, qui est la première invocation de méthode de la séquence.

Certaines machines virtuelles peuvent, dans certaines circonstances, omettre un ou plusieurs frameworks de stack de la trace de stack. Dans les cas extrêmes, une machine virtuelle ne disposant d’aucune information de trace de stack concernant ce jetable est autorisée à renvoyer un tableau de longueur nulle à partir de cette méthode. De manière générale, le tableau renvoyé par cette méthode contiendra un élément pour chaque image qui serait imprimée par printStackTrace. Les écritures dans le tableau renvoyé n’affectent pas les futurs appels à cette méthode.

Dans les commentaires, Peter Lawrey a trouvé la documentation mentionnant la limite par défaut de 1024 pour la taille de la stack:

Options de la machine virtuelle Java HotSpot

-XX: ThreadStackSize = 512

Taille de stack de threads (en kilo-octets). (0 signifie utiliser la taille de stack par défaut) [Sparc: 512; Solaris x86: 320 (auparavant 256 en 5.0 et versions antérieures); Sparc 64 bits: 1024; Linux amd64: 1024 (était égal à 0 dans la version 5.0 et les versions antérieures); tous les autres 0.]

Cependant, d’autres facteurs peuvent également jouer. Par exemple, ces questions mentionnent deux autres options:

  • Comment développer la taille de la trace de stack Java pour voir le bas de la stack? (déclenchant un débordement de stack) ( -XXMaxJavaStackTraceDepth )
  • Comment éviter les 1024 lignes de limite de stack d’exceptions Java ( -Xss )

Partie 1:

Dans l’implémentation OpenJDK , l’ implémentation println() se présente comme suit:

 public void println(Ssortingng x) { synchronized (this) { print(x); newLine(); } } 

Ainsi, l’appel à print(x) pourrait déborder de la stack et StackOverflowError serait StackOverflowError sans que la méthode newLine() ne soit appelée.

Partie 2:

De l’ API Java :

Certaines machines virtuelles peuvent, dans certaines circonstances, omettre un ou plusieurs frameworks de stack de la trace de stack … De manière générale, le tableau renvoyé par cette méthode contiendra un élément pour chaque cadre qui serait imprimé par printStackTrace.

Ainsi, la machine virtuelle Java est libre d’imposer une limite, telle que 1024, au nombre de trames de stack stockées dans la trace de stack.