Compartilhar via


Depurar erros do StackOverflow

A exceção StackOverflowException é gerada quando a pilha de execução estoura por conter excesso de chamadas de método aninhadas. Muitas vezes isso ocorre porque os métodos estão chamando uns aos outros recursivamente.

Por exemplo, suponha que você tenha um aplicativo da seguinte maneira:

using System;

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

O método Main chamará a si mesmo continuamente até que não haja mais espaço de pilha. Quando não houver mais espaço de pilha, a execução não poderá continuar e será gerado um 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>

Quando você vê o programa sair com uma saída como esta, você pode encontrar o código-fonte para os métodos de repetição e investigar a lógica que causa o grande número de chamadas.

Usando o depurador

Geralmente, apenas ver essa pilha de chamadas no console acima é suficiente para identificar o código problemático. No entanto, se o problema ainda não estiver claro, você poderá depurar ainda mais.

Este exemplo cria um core dump quando ocorre StackOverflowException. Depois, carrega o core dump no lldb (um depurador de linha de comando comum do Linux) e o depura.

  1. Execute o aplicativo com ele configurado para coletar um despejo de falha.

    > 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
    

    Nota

    O .NET 6 padroniza o prefixo DOTNET_ em vez de COMPlus_ para variáveis de ambiente que configuram o comportamento de tempo de execução do .NET. No entanto, o prefixo COMPlus_ continuará funcionando. Se você estiver usando uma versão anterior do runtime do .NET, ainda deverá usar o prefixo COMPlus_ para variáveis de ambiente.

  2. Instale a extensão SOS usando dotnet-sos.

    dotnet-sos install
    
  3. Abra o despejo no lldb e use o comando bt (backtrace) para exibir a pilha.

    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. O quadro superior 0x00007f59b40900cc é repetido várias vezes. Use o comando sosip2md para descobrir qual método gerenciado está localizado no endereço 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. Examine o método indicado temp.Program.Main(System.String[]) e a origem "/temp/Program.cs @ 9" para tentar descobrir o que o código fez de errado. Se forem necessárias informações adicionais, você poderá usar ferramentas de depuração adicionais ou comandos SOS para inspecionar o processo.