Debuggen von StackOverflow-Fehlern
Ein StackOverflowException wird ausgelöst, wenn der Ausführungsstapel überläuft, da er zu viele geschachtelte Methodenaufrufe enthält. Dies tritt sehr häufig auf, da Methoden rekursivaufrufen.
Angenommen, Sie haben eine App wie folgt:
using System;
namespace temp
{
class Program
{
static void Main(string[] args)
{
Main(args); // Oops, this recursion won't stop.
}
}
}
Die Main
-Methode ruft sich kontinuierlich auf, bis kein Stapelspeicher mehr vorhanden ist. Sobald kein Stapelspeicher mehr vorhanden ist, kann die Ausführung nicht fortgesetzt werden, sodass ein StackOverflowExceptionausgelöst wird.
> dotnet run
Stack overflow.
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
<this output repeats many more times>
Wenn das Programm mit der Ausgabe wie folgt beendet wird, können Sie den Quellcode für die wiederholten Methoden finden und die Logik untersuchen, die die große Anzahl von Aufrufen verursacht.
Verwenden des Debuggers
Häufig genügt es, diesen Aufrufstack auf der obigen Konsole zu sehen, um den problematischen Code zu identifizieren. Wenn das Problem jedoch noch unklar ist, können Sie das Problem weiter debuggen.
In diesem Beispiel wird ein Kernabbild erstellt, wenn die StackOverflowException auftritt, anschließend wird das Abbild in lldb (ein gängiger Linux-Befehlszeilendebugger) geladen und gedebuggt.
Führen Sie die App mit der Konfiguration zum Generieren eines Absturzabbilds aus.
> 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
Anmerkung
.NET 6 standardisiert das Präfix
DOTNET_
anstelle vonCOMPlus_
für Umgebungsvariablen, die das .NET-Laufzeitverhalten konfigurieren. Das PräfixCOMPlus_
funktioniert jedoch weiterhin. Wenn Sie eine frühere Version der .NET-Laufzeit verwenden, sollten Sie weiterhin das präfixCOMPlus_
für Umgebungsvariablen verwenden.Installieren Sie die SOS-Erweiterung mithilfe von dotnet-sos.
dotnet-sos install
Öffnen Sie den Dump in lldb und verwenden Sie den Befehl
bt
(Rückverfolgung), um den Stack 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 Rahmen
0x00007f59b40900cc
wird mehrmals wiederholt. Verwenden Sie den Befehl SOS-ip2md
, um herauszufinden, welche verwaltete Methode sich an 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
Schauen Sie sich die angegebene Methode temp an. Program.Main(System.String[]) und quelle "/temp/Program.cs @ 9", um festzustellen, ob Sie herausfinden können, was der Code falsch macht. Wenn zusätzliche Informationen erforderlich sind, können Sie weitere Debugger- oder SOS--Befehle verwenden, um den Prozess zu prüfen.