Entendendo a Stack (e a StackOverflowException)

Todas as linguagens modernas trabalham com duas regiões distintas de memória: Stack e Heap. Entretanto, temos percebido que poucas pessoas sabem apontar a distinição entre elas.

Nesse post, explicaremos a Stack, de forma incremental, a partir de seu propósito em dois cenários.

DISCLAIMER: Optamos por uma abordagem didática e, com certeza, omitimos muitos detalhes de como a Stack é implementada em linguagens, ambientes e sistemas operacionais modernos. Escolhemos simplicidade em lugar da precisão técnica.

Cenário 1 – Executando um programa simples

O programa que segue simplesmente imprime uma mensagem na tela.

public class Program
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
    }
}

Agora, tente imaginar como o computador executa esse programa.

Para começar, seria importante que a versão em binário (executável) estivesse devidamente carregada na memória. Certo?

NOTA: Na prática, em .NET (e em Java), não é isso que ocorre. Programas em .NET são carregados em uma representação intermediária, em Intermediate Language, sendo que cada método será convertido em código binário executável (assembly), apenas quando ocorrer sua primeira execução.

O computador precisaria manter um “ponteiro” apontando para a instrução a ser executada e, todas as instruções deveriam ser executadas sequencialmente, da primeira até a última.

Cenário 2 – Executando um programa mais complexo

O programa que segue utiliza uma abordagem recursiva (nada otimizada) para calcular o valor de um elemento da sequência de Fibonacci.

public class Program
{
    public static void Main()
    {
        System.Console.WriteLine(GetNthFibonacci(10));
    }

    public static int GetNthFibonacci(int n)  
    {  
        if ((n == 0) || (n == 1))  
        {  
            return n;  
        }  
        return GetNthFibonacci(n - 1) + GetNthFibonacci(n - 2);  
    }  
}

Da mesma forma como ocorreu anteriormente, podemos imaginar esse programa inteiramente carregado na memória.

O problema é que, dessa vez, a execução é um pouco mais complexa. Não podemos simplesmente executar as instruções do programa, uma após a outra, até chegar ao fim.

No exemplo, o método Main aguarda por um retorno da função GetNthFibonacci que, por sua vez, se executa recursivamente para chegar a uma resposta.

Em toda execução (recursiva), de GetNthFibonacci, o valor do parâmetro é diferente. Além disso, sempre que uma chamada recursiva se encerra, o programa precisa voltar ao ponto em que a chamada ocorreu, com o retorno apropriado, recuperando os valores das variáveis locais.

Para poder permitir que um método chame outros, recursivamente ou não, linguagens, ambientes e sistemas operacionais utilizam estrutura de dados peculiar, em uma região distinta da memória: a stack.

O que é a Stack?

A stack, no contexto deste post, é a estrutura de dados preservada em uma região distinta da memória que permite, entre outras coisas, que, em nossos códigos, métodos chamem outros métodos (funções), e continuem suas execuções assim que ocorrer um retorno, preservando variáveis locais.

Cada vez que chamamos um método, um “registro” (stack/activation frame) é empilhado nessa estrutura. Nesse registro estão:

  • Os argumentos que foram passados para o método
  • O endereço de retorno. Ou seja, o endereço de memória onde está a instrução que deverá ser executada quando o método concluir sua execução.
  • As variáveis locais que serão utilizadas no método.

Quando a execução de um método se encerra, esse registro é desempilhado (liberando a stack), o ponteiro de execução é movido para a posição da memória indicada pelo “endereço de retorno” e a execução continua daquele ponto.

Quando um método precisa consultar o valor de um argumento, ele acessa seu respectivo “stack frame” e recupera esse valor. O mesmo ocorre para variáveis locais.

O valor de um argumento ou de uma variável local poderá ser literal (como ocorre com tipos primitivos e structs) ou ser uma referência para um valor que está em outra região da memória (a heap, que é tema para outro post).

Importante destacar que todos os valores literais em um stack frame são descartados assim que este for desempilhado.

O que é a StackOverflowException?

O montante de memória destinado para manter a Stack costuma ser limitado. Quando ocorre a chamada de muitos métodos em cadeia, diversos stack frames vão sendo empilhados esgotando, eventualmente, a memória disponível para a Stack. Nesses casos, em .NET, isso gera uma StackOverflowException.

Não há como contornar essa exception. Afinal, um limite foi ultrapassado. Se seu programa está gerando essa exception, você precisará repensar sua implementação.

Concluindo…

Nesse post, apresentei, de forma bastante superficial, o que é a Stack e porque ela é importante.

Como advertimos no início, não nos preocupamos com rigor técnico. Optamos por usar uma abordagem didática. Esperamos que você tenha gostado.

Deixe suas dúvidas e considerações nos comentários.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
4 Comentários
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Flavio Spedaletti
Flavio Spedaletti
5 anos atrás

Ótimo post!
Como disseram, vale a pena escreverem sobre a heap também 🙂

Elemar Júnior
Elemar Júnior
5 anos atrás
Leandro
Leandro
5 anos atrás

Interessante deixar algumas biografias como recomendação para estudos sobre os assuntos abordados.

Jesse
Jesse
5 anos atrás

Elemar, em que situações, você sugere usar a alocação de memória Stack?

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
4
0
Queremos saber a sua opinião, deixe seu comentáriox
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Entendendo a Stack (e a StackOverflowException)

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Entendendo a Stack (e a StackOverflowException)

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?