Depuración de errores de StackOverflow
Se produce una excepción StackOverflowException cuando la pila de ejecución se desborda debido a que contiene demasiadas llamadas a métodos anidadas.
Por ejemplo, supongamos que tiene la siguiente aplicación:
using System;
namespace temp
{
class Program
{
static void Main(string[] args)
{
Main(args); // Oops, this recursion won't stop.
}
}
}
El método Main
se llamará a sí mismo continuamente hasta que no haya más espacio de pila. Cuando ya no haya más espacio de pila, no se podrá continuar con la ejecución y, por tanto, se producirá una excepción StackOverflowException.
> dotnet run
Stack overflow.
Nota
En .NET 5 y versiones posteriores, la pila de llamadas se envía a la consola.
Nota
En este artículo se describe cómo depurar un desbordamiento de pila con LLDB. Si usa Windows, se recomienda depurar la aplicación con Visual Studio o Visual Studio Code.
Ejemplo
Ejecute la aplicación con la configuración para recopilar un volcado de memoria durante un bloqueo.
> export DOTNET_DbgEnableMiniDump=1 > dotnet run Stack overflow. Writing minidump with heap to file /tmp/coredump.6412 Written 58191872 bytes (14207 pages) to core file
Nota:
.NET 6 estandariza en el prefijo
DOTNET_
en lugar de enCOMPlus_
para las variables de entorno que configuran el comportamiento en tiempo de ejecución de .NET. Sin embargo, el prefijoCOMPlus_
seguirá funcionando. Si usa una versión anterior del runtime de .NET, debe seguir usando el prefijoCOMPlus_
para las variables de entorno.Instale la extensión SOS mediante dotnet-sos.
dotnet-sos install
Depure el volcado de memoria en LLDB para ver la pila con errores.
lldb --core /temp/coredump.6412 (lldb) bt ... frame #261930: 0x00007f59b40900cc frame #261931: 0x00007f59b40900cc frame #261932: 0x00007f59b40900cc frame #261933: 0x00007f59b40900cc frame #261934: 0x00007f59b40900cc frame #261935: 0x00007f5a2d4a080f libcoreclr.so`CallDescrWorkerInternal at unixasmmacrosamd64.inc:867 frame #261936: 0x00007f5a2d3cc4c3 libcoreclr.so`MethodDescCallSite::CallTargetWorker(unsigned long const*, unsigned long*, int) at callhelpers.cpp:70 frame #261937: 0x00007f5a2d3cc468 libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=<unavailable>, pArguments=0x00007ffe8222e7b0, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:604 frame #261938: 0x00007f5a2d4b6182 libcoreclr.so`RunMain(MethodDesc*, short, int*, PtrArray**) [inlined] MethodDescCallSite::Call(this=<unavailable>, pArguments=<unavailable>) at callhelpers.h:468 ...
El marco superior
0x00007f59b40900cc
se repite varias veces. Use el comando SOSip2md
para averiguar qué método se encuentra en la dirección0x00007f59b40900cc
.(lldb) ip2md 0x00007f59b40900cc MethodDesc: 00007f59b413ffa8 Method Name: temp.Program.Main(System.String[]) Class: 00007f59b4181d40 MethodTable: 00007f59b4190020 mdToken: 0000000006000001 Module: 00007f59b413dbf8 IsJitted: yes Current CodeAddr: 00007f59b40900a0 Version History: ILCodeVersion: 0000000000000000 ReJIT ID: 0 IL Addr: 0000000000000000 CodeAddr: 00007f59b40900a0 (MinOptJitted) NativeCodeVersion: 0000000000000000 Source file: /temp/Program.cs @ 9
Vaya al método temp.Program.Main(System.String[]) indicado y al origen "/temp/Program.cs @ 9" para tratar de averiguar qué hizo mal. Si todavía no lo tiene claro, puede agregar funciones de registro en esa área del código.