Sdílet prostřednictvím


Ladění chyb StackOverflow

Vyvolá StackOverflowException se při přetečení zásobníku provádění, protože obsahuje příliš mnoho volání vnořených metod.

Předpokládejme například, že máte aplikaci takto:

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 k dispozici žádné další místo v zásobníku. Jakmile není k dispozici další místo v zásobníku StackOverflowException, provádění nemůže pokračovat, a proto vyvolá výjimku .

> dotnet run
Stack overflow.

Poznámka

V .NET 5 a novějších verzích se do konzoly vypíše nástroj pro volání.

Poznámka

Tento článek popisuje, jak ladit přetečení zásobníku pomocí lldb. Pokud používáte Windows, doporučujeme aplikaci ladit pomocí sady Visual Studio nebo editoru Visual Studio Code.

Příklad

  1. Spusťte aplikaci s nakonfigurovanou tak, aby při chybovém ukončení shromáždila výpis paměti.

    > 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ísto COMPlus_ pro proměnné prostředí, které konfigurují chování za běhu .NET. Předpona COMPlus_ ale bude i nadále fungovat. Pokud používáte předchozí verzi modulu runtime .NET, měli byste stále používat předponu COMPlus_ pro proměnné prostředí.

  2. Instalace rozšíření SOS pomocí příkazu dotnet-sos

    dotnet-sos install
    
  3. Laděním výpisu paměti v databázi lldb zobrazte zásobník, který selhal.

    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
    ...
    
  4. Horní snímek 0x00007f59b40900cc se několikrát opakuje. Pomocí příkazu SOSip2md zjistěte, jaká metoda se nachází na 0x00007f59b40900cc adrese.

    (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
    
  5. Podívejte se na uvedenou metodu temp. Program.Main(System.String[]) a zdroj "/temp/Program.cs @ 9", abyste zjistili, co jste udělali špatně. Pokud to stále nebylo jasné, můžete do této oblasti kódu přidat protokolování.

Viz také