Memória de Stack e Heap no .NET com exemplos
- #.NET C#
Memória de Stack e Heap no .NET com exemplos
Como parte deste artigo, primeiro, discutiremos o que acontece internamente quando declaramos uma variável de tipos de valor e tipos de referência. Em seguida, vamos avançar e aprender dois conceitos importantes, ou seja, memória de stack e heap, e falar sobre tipos de valor e tipos de referência.
O que acontece internamente quando declaramos uma variável em um aplicativo .NET?
Quando declaramos uma variável em um aplicativo .NET, ela aloca alguma memória na RAM. A memória que ele aloca na RAM tem três coisas são as seguintes: Nome da variável, o tipo de dados da variável e o Valor da variável.
Para uma melhor compreensão, dê uma olhada na imagem a seguir. Aqui, declaramos uma variável do tipo int e atribuímos um valor 10.
Memória RAM
int i = 10;
tipo int
nome i
valor 10
Declarada a variável i e atribuindo um valor temos uma visão geral de alto nível do que está acontecendo na memória. Mas, dependendo do tipo de dados (ou seja, dependendo do tipo de valor e do tipo de referência), a memória pode ser alocada na stack ou na memória de heap.
Noções básicas sobre memória de stack e heap em C#:
Existem dois tipos de alocação de memória para as variáveis que criamos no aplicativo .NET, ou seja, memória de stack e memória de heap. Para entender as diferenças entre Stack e Heap, dê uma olhada no código a seguir, e vamos entender o que realmente acontece no código abaixo internamente.
Imagem 1
Como você pode observar na Imagem 1, o MetodoExemplo tem três instruções. Vamos entender declaração por declaração como as coisas são executadas internamente.
Instrução 1:
Quando a primeira instrução é executada, o compilador aloca alguma memória na Stack. A memória de Stack é responsável por manter o controle da memória em execução necessária em seu aplicativo. Para uma melhor compreensão, dê uma olhada na imagem 2 a seguir.
Imagem 2
Instrução 2:
Quando a segunda instrução é executada, ela empilha essa alocação de memória (alocação de memória para a variável y) sobre a primeira alocação de memória (alocação de memória para a variável x). Você pode pensar na Stack como uma pilha de pratos ou pratos colocados uns sobre os outros. Olhe na imagem 3 a seguir para uma melhor compreensão.
Imagem 3
A alocação e desalocação de memória de pilha no .NET usa o princípio LIFO - Last In, First Out (Última entrada, primeira saída). Em outras palavras, podemos dizer que a alocação e a desalocação de memória são feitas apenas em uma extremidade da memória, ou seja, no topo da pilha.
Instrução 3:
Criamos um objeto de AlgumaClasse. Quando a terceira instrução é executada, ela cria internamente um ponteiro na memória de stack e o objeto real é armazenado em um local de memória diferente chamado memória heap. O local de memória de heap não rastreia a memória em execução. O heap é usado para alocação dinâmica de memória. Para uma melhor compreensão, dê uma olhada na imagem 4.
Imagem 4
Os ponteiros de referência são alocados na Stack. A instrução, AlgumaClasse cls1,não aloca memória para uma instância de AlgumaClasse. Ele apenas aloca uma variável com o nome cls1 na pilha e define seu valor como nulo. Quando ele atinge a nova palavra-chave, ele aloca memória no heap.
O que acontece quando o método conclui sua execução?
Quando as três instruções são executadas, o controle sairá do método. Quando ele passa o controle de extremidade, ou seja, a chave final "}", ele limpará todas as variáveis de memória criadas na pilha. Ele desalojará a memória da stack de uma forma 'LIFO'.
Por que temos dois tipos de memórias?
No C#, tipos de dados primitivos, como int, double, bool, etc., mantêm um único valor. Por outro lado, os tipos de dados de referência ou tipos de dados de objeto são complexos, ou seja, um tipo de dados de objeto ou tipo de dados de referência pode ter referência a outros objetos e outros tipos de dados primitivos.
Assim, o tipo de dados de referência contém referências a outros valores múltiplos, e cada um deles deve ser armazenado na memória. Os tipos de objeto precisam de memória dinâmica, enquanto os tipos de dados primitivos precisam de memória estática.
Pontos importantes a serem destacados
Sobre a memória stack
- Alocação: A memória stack é alocada para alocação estática e variáveis locais. Ela é gerenciada pela CPU, tornando-o mais rápido e eficiente.
- Uso: Quando um método é chamado, um bloco de memória (um quadro de pilha) é alocado na stack para suas variáveis e parâmetros locais. Quando a chamada de método retorna, o bloco não é usado e pode ser usado para a próxima chamada de método.
- Vida útil: As variáveis armazenadas na stack só estão disponíveis durante o tempo de vida da chamada do método. Ou seja, terminou a execução ela é descartada (o coletor de lixo se responsabiliza pela finalização).
- Tipo de dados: Ela armazena tipos de valor em C#. Isso inclui tipos de dados primitivos (como int, double, char), structs e referências a objetos (as próprias referências, não os objetos).
Sobre a memória heap
- Alocação: A memória de heap é usada para alocação dinâmica de memória, que inclui objetos e estruturas de dados complexas que exigem mais flexibilidade e são gerenciadas pelo coletor de lixo no .NET.
- Uso: Os objetos são alocados no heap e a memória é gerenciada em tempo de execução. Novos objetos são criados usando a nova palavra-chave e o coletor de lixo libera automaticamente memória de heap quando os objetos não estão mais em uso.
- Vida útil: Os objetos na pilha vivem desde quando são criados até que não sejam mais usados e sejam coletados lixo.
- Tipo de dados: Ele armazena tipos de referência como objetos, matrizes e instâncias de classe.
Principais diferenças
- Gestão: A memória stack é gerenciada automaticamente pelo sistema, enquanto a memória de heap é alocada dinamicamente e desalocada pelo coletor de lixo.
- Velocidade: A memória de stack é geralmente mais rápida do que a memória de heap devido à sua organização e à forma como é gerida.
- Tamanho: A stack tem limites de tamanho com base no thread, mas o heap pode crescer dinamicamente conforme necessário (limitado pela memória disponível do sistema).
- Acesso: O acesso à memória de stack é mais simples e rápido, enquanto a memória de heap requer um gerenciamento mais complexo.
- Armazenamento: Os tipos de valor são armazenados na memória stack, enquanto os tipos de referência são armazenados na memória de heap.
Neste artigo, tentei explicar como funciona o uso da memória através de um exemplo prático em C#.
Espero que tenha gostado. Até a próxima.