StackOverflowException en .NET

Después de golpear algunos StackOverflowExceptions en .NET noté que omiten por completo los manejadores de excepciones no controlados que .NET ofrece (Application.ThreadException / AppDomain.UnhandledException). Esto es muy inquietante ya que tenemos un código de limpieza crítico en esos manejadores de excepciones.

¿Hay alguna forma de superar esto?

Realmente no; un desbordamiento de stack, o una excepción de memoria insuficiente dentro del CLR en sí significa que algo se ha tornado críticamente incorrecto (generalmente lo obtengo cuando he sido un imbécil y he creado una propiedad recursiva).

Cuando se produce este estado, no hay forma de que el CLR asigne nuevas llamadas a funciones o memoria para permitirle llamar a los manejadores de excepciones; es un escenario de “debemos detenernos ahora “.

Sin embargo, si lanza la excepción usted mismo será llamado a sus manejadores de excepciones.

Hay tres tipos de llamadas “excepciones asincrónicas”. Esa es la excepción ThreadAbortException, la OutOfMemoryException y la StackOverflowException mencionada. Esas excepciones pueden ocurrir en cualquier instrucción en su código.

Y, también hay una manera de superarlos:

La más fácil es la ThreadAbortException. Cuando el código actual se ejecuta en un bloque final. ThreadAbortExceptions se “mueve” al final del bloque finally. Entonces, todo en un bloque final no puede ser abortado por una ThreadAbortException.

Para evitar una excepción OutOfMemoryException, solo tiene una posibilidad: no asigne nada en el Heap. Esto significa que no tiene permitido crear ningún tipo de referencia nuevo.

Para superar StackOverflowException, necesita ayuda del Framework. Esta ayuda se manifiesta en regiones de ejecución restringida. La stack requerida se asigna antes de que se ejecute el código real y, además, también garantiza que el código ya está comstackdo en JIT y, por lo tanto, está disponible para su ejecución.

Hay tres formas de ejecutar código en regiones de ejecución restringida (copiadas del blog del equipo BCL ):

  • ExecuteCodeWithGuaranteedCleanup, una forma segura de desbordamiento de stack try / finally.
  • Un bloque try / finally precedido inmediatamente por una llamada a RuntimeHelpers.PrepareConstrainedRegions. El bloque try no está restringido, pero todos los lockings catch, finally y fault para ese bash son.
  • Como finalizador crítico: cualquier subclase de CriticalFinalizerObject tiene un finalizador preparado con entusiasmo antes de que se asigne una instancia del objeto.
    • Un caso especial es el método ReleaseHandle de SafeHandle, un método virtual que se prepara ansiosamente antes de que se asigne la subclase, y se llama desde el finalizador crítico de SafeHandle.

Puede encontrar más en estas publicaciones de blog:

Regiones de ejecución restringida y otras erratas [Brian Grunkemeyer] en el Blog del equipo BCL.

El Weblog de Joe Duffy sobre Atomicity y fallas de excepción asíncronas ofrece una muy buena visión general sobre las excepciones asincrónicas y la solidez en el .NET Framework.

Un stackoverflow no es algo de lo que pueda recuperarse, ya que no puede asignar más memoria de stack incluso para llamar a su manejador de excepciones.

Lo único que puede hacer es rastrear la causa y evitar que ocurra (p.ej. cuidado con la recursión y no asignar objetos grandes en la stack).

blowdart lo clavó, arriba. Dumbass recursivo de propiedad, como le gusta llamarlo. Realmente solo es un problema con escribir el código demasiado rápido.

private Thing _myThing = null; Public Thing MyThing { get{ return this.MyThing;} set{ this.MyThing = value;} }