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.
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 deCOMPlus_
pour les variables d’environnement qui configurent le comportement d’exécution de .NET. Toutefois, le préfixeCOMPlus_
continuera de fonctionner. Si vous utilisez une version précédente du runtime .NET, vous devez toujours utiliser le préfixeCOMPlus_
pour les variables d’environnement.Installez l'extension SOS en utilisant dotnet-sos.
dotnet-sos install
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 ...
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’adresse0x00007f59b40900cc
.(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
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.