¿Está * alguna vez * bien atrapar StackOverflowError en Java?

27

Solía ​​pensar que no, pero ayer tuve que hacerlo. Es una aplicación que utiliza Akka (una implementación del sistema de actores para la JVM) para procesar trabajos asincrónicos. Uno de los actores realiza alguna manipulación de PDF, y debido a que la biblioteca tiene errores, muere con un de StackOverflowErrorvez en cuando.

El segundo aspecto es que Akka está configurado para apagar todo su sistema de actores si se detecta algún error fatal de JVM (por ejemplo, StackOverflowError).

El tercer aspecto es que este sistema de actor está incrustado dentro de una aplicación web (por WTF-ish, legacy, razones), por lo que cuando el sistema de actor se cierra, la aplicación web no lo está. El efecto neto es que StackOverflowErrornuestra aplicación de procesamiento de trabajo se convierte en una aplicación web vacía.

Como una solución rápida, tuve que atrapar el StackOverflowErrorlanzamiento, para que el grupo de hilos del sistema de actores no se derribara. Esto me lleva a pensar que tal vez a veces está bien detectar tales errores, especialmente en contextos como este. ¿Cuándo hay un grupo de subprocesos que procesa tareas arbitrarias? A diferencia de un, OutOfMemoryErrorno puedo imaginar cómo StackOverflowErrorpuede dejar una aplicación en un estado inconsistente. La pila se borra después de tal error, por lo que el cálculo puede continuar normalmente. Pero tal vez me estoy perdiendo algo importante.

Además, tenga en cuenta que estoy dispuesto a corregir el error en primer lugar (de hecho, ya he arreglado un SOE en esta misma aplicación hace unos días), pero realmente no sé cuándo esto tipo de situación puede surgir.

¿Por qué sería mejor reiniciar el proceso JVM en lugar de detectarlo StackOverflowError, marcar ese trabajo como fallido y continuar con mi negocio?

¿Hay alguna razón convincente para nunca atrapar a las empresas estatales? Excepto "mejores prácticas", que es un término vago que no me dice nada.

Ionuț G. Stan
fuente
1
Otra opción sería aumentar el espacio de pila disponible en la JVM
Ratchet Freak
3
@ratchetfreak: StackOverflowExceptions generalmente se debe a una cadena de llamadas de método que no termina - aumentar el espacio de la pila aumentaría el costo de memoria de un nuevo subproceso sin ningún beneficio.
jhominal
1
Al menos un SOE era legítimo porque la entrada era muy grande. Desafortunadamente, manejarlo con una implementación recursiva (regex impl. De Java) no fue una muy buena idea. De todos modos, incluso cuando se garantiza que el cálculo terminará, no sabes si el nuevo tamaño de la pila es lo suficientemente grande como para otros cálculos.
Ionuț G. Stan
2
¿No debería migrar esto a Sta ... Oh, espera ... no importa. :-)
Blrfl
En cuanto a su biblioteca con errores. Realmente deberías migrar esa función de manipulación de PDF a su propio proceso para que puedas dejar que el sistema operativo la mate.
Esben Skov Pedersen

Respuestas:

44

Como regla general, si nunca fuera absolutamente aceptable hacer algo, y hubiera un acuerdo al respecto, los implementadores del lenguaje no lo habrían permitido. Casi no hay tales máximas unánimemente claras. (Afortunadamente, ¡eso es lo que nos mantiene a los programadores humanos en trabajos!)

Parece que ha encontrado una situación en la que detectar este error es la mejor opción para usted: permite que su aplicación funcione, mientras que todas las demás alternativas no lo hacen, y eso es lo que cuenta al final. Todas las "mejores prácticas" son simples sumas de largas experiencias con muchos casos que generalmente se pueden usar en lugar de un análisis detallado de un caso específico para ahorrar tiempo; en su caso, ya realizó el análisis específico y obtuvo un resultado diferente. ¡Felicidades, eres capaz de pensar de forma independiente!

(Dicho esto, seguramente hay situaciones en las que un desbordamiento de la pila puede dejar una aplicación inconsistente al igual que un agotamiento de memoria. Imagine que se construye algún objeto y luego se inicializa con la ayuda de llamadas a métodos internos anidados; si uno de ellos arroja, el objeto puede muy bien estar en un estado que no se supone que sea posible, como si una asignación hubiera fallado. Pero eso no significa que su solución no pueda ser la mejor).

Kilian Foth
fuente
3
Gracias. Mis dudas se reforzaron un poco después de descubrir que .NET hizo StackOverflowExceptionuna excepción no detectable. Lo sé, es una plataforma diferente, pero pensé que podrían haber tenido una razón. Además, su punto con respecto a la inicialización de objetos es perfecto. Esto me lleva a pensar que debería captar este SOE algunas capas de abstracción a continuación, para no captar el SOE "incorrecto".
Ionuț G. Stan
14
+1: las mejores prácticas siempre deben venir con explicaciones de por qué y en qué contexto son "mejores", para que pueda juzgar si se aplican a su caso específico.
Michael Borgwardt
situations heredebería ser situations where.
Servy
2

No sé si hay riesgos específicos de JVM aquí, pero en general parece bastante razonable.

Por ejemplo, existen algoritmos recursivos, como la selección rápida ingenua, que tienen una log(n)profundidad de pila en un caso típico, pero en el peor de los casos se degradan a una profundidad nque puede hacer explotar la pila.

El peor de los casos es raro, y es poco probable que vuelva a suceder si reinicia la ordenación en el conjunto parcialmente ordenado, por lo que tiene mucho sentido detectar una excepción de desbordamiento de pila cuando ocurre y reiniciar el trabajo en lugar de tratar de evitar que ocurra un error o mate Aplicación completa.

Kornel
fuente