Partage via


Déboguer des erreurs StackOverflow

Une StackOverflowException est levée quand la capacité de la pile d'exécution est dépassée en raison d'un trop grand nombre d'appels à la méthode imbriquée. Très souvent, cela se produit parce que les méthodes appellent les unes les autres de manière récursive.

Par exemple, supposons que vous disposez d’une application comme suit :

using System;

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

La méthode Main s'appelle en permanence jusqu'à ce qu'il n'y ait plus d'espace de pile. Une fois qu'il n'y a plus d'espace de pile, l'exécution ne peut pas continuer et lève donc une 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>

Lorsque vous voyez la sortie du programme avec une sortie comme celle-ci, vous pouvez trouver le code source de la ou des méthodes répétées et examiner la logique qui provoque le grand nombre d’appels.

Utilisation du débogueur

Il suffit souvent de voir cette pile d’appels sur la console ci-dessus pour identifier le code problématique. Toutefois, si le problème n’est toujours pas clair, vous pouvez déboguer davantage.

Cet exemple crée un dump du noyau lorsque l'exception StackOverflow se produit, puis charge le dump dans lldb (un débogueur de ligne de commande Linux courant) et le débogue.

  1. Exécutez l'application en la configurant pour qu'elle collecte un dumpage en cas de plantage.

    > 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
    

    Remarque

    .NET 6 standardise le préfixe DOTNET_ au lieu de COMPlus_ pour les variables d’environnement qui configurent le comportement d’exécution de .NET. Toutefois, le préfixe COMPlus_ continuera de fonctionner. Si vous utilisez une version précédente du runtime .NET, vous devez toujours utiliser le préfixe COMPlus_ pour les variables d’environnement.

  2. Installez l'extension SOS en utilisant dotnet-sos.

    dotnet-sos install
    
  3. Ouvrez le dump dans lldb et utilisez la commande bt (backtrace) pour afficher la pile.

    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. Le cadre supérieur 0x00007f59b40900cc est répété plusieurs fois. Utilisez la commande SOSip2md pour déterminer quelle méthode managée se trouve à l’adresse 0x00007f59b40900cc.

    (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. Examinez la méthode indiquée temp.Program.Main(System.String[]) et la source "/temp/Program.cs @ 9" pour voir si vous pouvez comprendre ce qui ne va pas dans le code. Si des informations supplémentaires sont nécessaires, vous pouvez utiliser d'autres commandes du débogueur ou de SOS pour inspecter le processus.