Delen via


Fouten in StackOverflow opsporen

Er wordt een StackOverflowException opgeworpen wanneer de uitvoeringsstack overloopt omdat deze te veel geneste methode-aanroepen bevat. Dit gebeurt vaak omdat methoden elkaar aanroepen recursief.

Stel dat u een app als volgt hebt:

using System;

namespace temp
{
    class Program
    {
        static void Main(string[] args)
        {
            Main(args); // Oops, this recursion won't stop.
        }
    }
}

De methode Main roept zichzelf continu aan totdat er geen stackruimte meer is. Zodra er geen stapelruimte meer is, kan het proces niet doorgaan en wordt er dus een 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>

Wanneer u ziet dat het programma wordt afgesloten met uitvoer zoals deze, kunt u de broncode voor de herhalende methode(s) vinden en de logica onderzoeken die het grote aantal aanroepen veroorzaakt.

Het foutopsporingsprogramma gebruiken

Vaak is het voldoende om deze aanroepstack op de bovenstaande console te zien om de problematische code te identificeren. Als het probleem echter nog steeds onduidelijk is, kunt u verder fouten opsporen.

In dit voorbeeld wordt een kerndump gemaakt wanneer de StackOverflowException plaatsvindt, waarna de dump wordt geladen in lldb (een veelgebruikte Linux command-line debugger) en vervolgens worden fouten opgespoord.

  1. Voer de app uit met deze geconfigureerd om een dump te verzamelen bij een crash.

    > 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
    

    Notitie

    .NET 6 standaardiseert het voorvoegsel DOTNET_ in plaats van COMPlus_ voor omgevingsvariabelen die .NET-runtimegedrag configureren. Het voorvoegsel COMPlus_ blijft echter werken. Als u een eerdere versie van de .NET-runtime gebruikt, moet u nog steeds het COMPlus_ voorvoegsel voor omgevingsvariabelen gebruiken.

  2. Installeer de SOS-extensie met dotnet-sos.

    dotnet-sos install
    
  3. Open de dump in lldb en gebruik de opdracht bt (backtrace) om de stack weer te geven.

    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. Het bovenste frame 0x00007f59b40900cc wordt meerdere keren herhaald. Gebruik de opdracht SOSip2md om erachter te komen welke beheerde methode zich op het 0x00007f59b40900cc adres bevindt.

    (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. Bekijk de aangegeven methode temp. Program.Main(System.String[]) en bron "/temp/Program.cs @ 9" om te zien of u kunt achterhalen wat de code verkeerd doet. Als er aanvullende informatie nodig is, kunt u verder foutopsporingsprogramma of SOS opdrachten gebruiken om het proces te inspecteren.