Debuggen von StackOverflow-Fehlern
Eine StackOverflowException-Ausnahme wird bei einem Überlauf des Ausführungsstapels durch zu viele geschachtelte Methodenaufrufe ausgelöst.
Nehmen Sie beispielsweise an, Sie hätten folgende App:
using System;
namespace temp
{
class Program
{
static void Main(string[] args)
{
Main(args); // Oops, this recursion won't stop.
}
}
}
Die Main
-Methode ruft sich fortlaufend selbst auf, bis kein Stapelspeicher mehr vorhanden ist. Wenn kein Stapelspeicher mehr vorhanden ist, kann die Ausführung nicht fortgesetzt werden, und es wird eine StackOverflowException-Ausnahme ausgelöst.
> dotnet run
Stack overflow.
Hinweis
Bei .NET 5 und höher wird die Aufrufliste an die Konsole ausgegeben.
Hinweis
In diesem Artikel wird beschrieben, wie Sie einen Stapelüberlauf mit lldb debuggen. Wenn die Ausführung unter Windows erfolgt, empfiehlt es sich, die App mit Visual Studio oder Visual Studio Code zu debuggen.
Beispiel
Ausführen der App mit der Konfiguration zum Sichern eines Absturzabbilds
> 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
Hinweis
In .NET 6 ist das Präfix
DOTNET_
stattCOMPlus_
Standard für Umgebungsvariablen, die das .NET-Runtimeverhalten konfigurieren. Das PräfixCOMPlus_
funktioniert jedoch weiterhin. Wenn Sie eine frühere Version der .NET-Runtime verwenden, sollten Sie weiterhin das PräfixCOMPlus_
für Umgebungsvariablen verwenden.Installieren der SOS-Erweiterung mithilfe von dotnet-sos
dotnet-sos install
Debuggen des Abbilds in lldb, um den fehlerhaften Stapel anzuzeigen
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 ...
Der obere Frame
0x00007f59b40900cc
wird mehrmals wiederholt. Verwenden Sie den Befehl SOSip2md
, um herauszufinden, welche Methode sich unter der0x00007f59b40900cc
-Adresse befindet.(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
Sehen Sie sich die angegebene Methode „temp.Program.Main(System.String[])“ und die Quelle „/temp/Program.cs @ 9“ an, um zu ermitteln, ob Sie feststellen können, was Sie falsch gemacht haben. Wenn es immer noch nicht klar ist, können Sie die Protokollierung in diesem Bereich des Codes hinzufügen.