Ladění chyb StackOverflow
StackOverflowException je vyvolán při přetečení zásobníku provádění kvůli příliš mnoha vnořeným voláním metody. Velmi často k tomu dochází, protože metody navzájem volají rekurzivně.
Předpokládejme například, že máte aplikaci v následující podobě:
using System;
namespace temp
{
class Program
{
static void Main(string[] args)
{
Main(args); // Oops, this recursion won't stop.
}
}
}
Metoda Main
bude neustále volat sama sebe, dokud nebude zásobník plný. Jakmile není více prostoru zásobníku, spuštění nemůže pokračovat, a proto vyvolá StackOverflowException.
> 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>
Když se zobrazí ukončení programu s výstupem, jako je tento, můžete najít zdrojový kód pro opakující se metody a prozkoumat logiku, která způsobuje velký počet volání.
Použití ladicího programu
Často stačí vidět tento zásobník volání na konzoli výše k identifikaci problematického kódu. Pokud problém stále není jasný, můžete pokračovat v ladění.
Tento příklad vytvoří základní výpis paměti při výskytu StackOverflowException, pak načte výpis paměti do lldb (běžný ladicí program příkazového řádku Linuxu) a ladí ho.
Spusťte aplikaci nakonfigurovanou tak, aby při pádu shromažďovala výpis.
> 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
Poznámka
.NET 6 standardizuje předponu
DOTNET_
místoCOMPlus_
pro proměnné prostředí, které konfigurují chování za běhu .NET. PředponaCOMPlus_
ale bude i nadále fungovat. Pokud používáte předchozí verzi modulu runtime .NET, měli byste stále používat předponuCOMPlus_
pro proměnné prostředí.Nainstalujte rozšíření SOS pomocí dotnet-sos.
dotnet-sos install
Otevřete výpis paměti v lldb a pomocí příkazu
bt
(backtrace) zobrazte zásobník.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 ...
Horní rámec
0x00007f59b40900cc
se několikrát opakuje. Pomocí příkazu SOSip2md
zjistěte, jaká spravovaná metoda se nachází na adrese0x00007f59b40900cc
.(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
Podívejte se na uvedenou metodu temp. Program.Main(System.String[]) a zdroj /temp/Program.cs @ 9, abyste zjistili, jestli kód dělá špatně. Pokud potřebujete další informace, můžete použít ladicí program nebo příkazy SOS ke zkoumání procesu.