Je pensais que non, mais hier, je devais le faire. Il s'agit d'une application qui utilise Akka (une implémentation de système d'acteur pour la JVM) pour traiter les travaux asynchrones. L'un des acteurs effectue une manipulation PDF, et parce que la bibliothèque est boguée, elle meurt de StackOverflowError
temps en temps.
Le deuxième aspect est qu'Akka est configuré pour arrêter tout son système d'acteurs si une erreur fatale JVM (par exemple StackOverflowError) est détectée.
Le troisième aspect est que ce système d'acteur est intégré dans une application Web (pour WTF-ish, héritage, raisons), donc lorsque le système d'acteur est arrêté, l'application Web ne l'est pas. L'effet net est que sur StackOverflowError
notre application de traitement des travaux devient juste une application Web vide.
En guise de solution rapide, j'ai dû attraper le StackOverflowError
lancer, afin que le pool de threads du système d'acteurs ne soit pas démoli. Cela m'amène à penser que c'est peut-être parfois correct de détecter de telles erreurs, en particulier dans des contextes comme celui-ci? Lorsqu'il existe un pool de threads traitant des tâches arbitraires? Contrairement à un, OutOfMemoryError
je ne peux pas imaginer comment un StackOverflowError
peut laisser une application dans un état incohérent. La pile est effacée après une telle erreur, donc le calcul peut continuer normalement. Mais peut-être que je manque quelque chose d'important.
De plus, notons que je suis tout à fait d'accord pour corriger l'erreur en premier lieu (en fait, j'ai déjà corrigé un SOE dans cette même application il y a quelques jours), mais je ne sais vraiment pas quand cela genre de situation pourrait survenir.
Pourquoi serait-il préférable de redémarrer le processus JVM au lieu de le rattraper StackOverflowError
, de marquer ce travail comme ayant échoué et de poursuivre mon entreprise?
Y a-t-il une raison impérieuse de ne jamais attraper les entreprises publiques? Sauf «meilleures pratiques», qui est un terme vague qui ne me dit rien.
la source
StackOverflowException
s sont généralement dus à une chaîne non terminale d'appels de méthode - augmenter l'espace de la pile augmenterait alors le coût de la mémoire d'un nouveau thread sans aucun avantage.:-)
Réponses:
En règle générale, s'il n'était absolument jamais, jamais acceptable de faire quelque chose, et qu'il y avait un accord à ce sujet, les implémenteurs de langage ne l'auraient pas autorisé. Il n'y a presque pas de maximes aussi claires à l'unanimité. (Heureusement, parce que c'est ce qui nous maintient en tant que programmeurs humains dans les emplois!)
Il semble que vous ayez trouvé une situation où la capture de cette erreur est la meilleure option pour vous: cela permet à votre application de fonctionner, contrairement à toutes les autres alternatives, et c'est ce qui compte au final. Toutes les "meilleures pratiques" ne sont que des résumés de longues expériences avec de nombreux cas qui peuvent généralement être utilisés à la place d'une analyse détaillée d'un cas spécifique pour gagner du temps; dans votre cas, vous avez déjà effectué l'analyse spécifique et obtenu un résultat différent. Félicitations, vous êtes capable d'une pensée indépendante!
(Cela dit, il y a sûrement des situations où un débordement de pile peut laisser une application incohérente tout comme l'épuisement de la mémoire. Imaginez simplement qu'un objet est construit puis initialisé à l'aide d'appels de méthodes internes imbriqués - si l'un d'eux lance, l'objet peut très bien être dans un état qui n'est pas censé être possible, tout comme si une allocation avait échoué. Mais cela ne signifie pas que votre solution ne pourrait pas encore être la meilleure.)
la source
StackOverflowException
une exception non capturable. Je sais, c'est une plateforme différente, mais je pensais qu'ils avaient peut-être une raison. En outre, votre point concernant l'initialisation d'objet est parfait. Cela m'amène à penser que je devrais attraper ce SOE quelques couches d'abstraction ci-dessous, afin que je n'attrape pas le "mauvais" SOE.situations here
devrait êtresituations where
.Je ne sais pas s'il y a des risques spécifiques à la JVM ici, mais dans l'ensemble, cela semble assez raisonnable.
Par exemple, il existe des algorithmes récursifs, comme le tri rapide naïf, qui ont
log(n)
une profondeur de pile dans un cas typique, mais dans le pire des cas, ils se dégradent à une profondeurn
qui peut faire exploser la pile.Le pire des cas est rare, et il est peu probable que cela se reproduise si vous redémarrez le tri sur l'ensemble partiellement trié, il est donc très logique d'attraper une exception de dépassement de pile quand cela se produit et de redémarrer le travail au lieu d'essayer d'empêcher qu'une erreur ne se produise ou ne tue demande complète.
la source