Hoje vamos recordar como é feito a alocação de memória para os tipos de dados na linguagem C# usando a memória Heap e a Stack. |
Na linguagem C# o compilador trata o gerenciamento de memória alocando espaço em
duas áeras, dependendo se o SO for 32 ou 64-bit:
Stack - Uma área de tamanho médio de 1 MB a 4 MB;
Heap - Uma área que pode ter Gigabytes de tamanho;
As variáveis definidas com os tipos de valor como int, bool, double, long, char, datetime, byte, structs, etc. são armazenadas na memória Stack. E os valores que essas variáveis contém ficam junto com elas na memória e podem ser acessadas diretamente.
Os valores das variáveis definidas como tipos de referência como string, object, class , interface, delegate, record são armazenados na memória Heap. E essas variáveis não contém os valores a elas atribuídos mas contém uma referência para uma área da memória onde o valor esta realmente armazenado.
Neste caso é criada uma referência da stack onde a variável esta definida para uma posição na memória Heap onde o valor dela esta armazenada.
Assim duas variáveis que usam tipos de referência podem fazer referência ao mesmo objeto; portanto, as operações em uma variável podem afetar o objeto referenciado pela outra variável.
Podemos destacar que a Stack é um array de memória que usa a estrutura de dados LIFO (Last in Firs Out) onde os dados podem ser incluidos e deletados a partir do topo.
Já a Heap é uma área onde 'porções' são alocadas para armazenar os tipos de dados onde os dados podem ser armazenados ou removidos em qualquer ordem.
A alocação de memória na Stack é estática enquanto que na Heap é dinâmica. E na stack as variáveis não podem ser redimensionadas enquanto que na Heap elas podem.
O acesso a Stack é mais rápido que o acesso a Heap.
A memória stack pode ser usada em uma thread de execução e a Heap pode ser usada por todas as partes da aplicação. Além disso as variáveis na stack são visíveis e acessíveis somente pela Thread proprietária enquanto que na Heap elas são visíveis e podem ser acessadas por todas as threads.
Para concluir temos uma figura que ilustra de forma simplificada o processo de alocação de memória para tipos de valor e tipos de referência :
A limpeza da memória Stack não é feita pelo Coletor de Lixo ou Garabe Collector(GC) as alocações e desalocações são feitas automaticamaticamaente assim que as variáveis locais perdem o escopo no programa.
Para a Heap o processo é o seguinte :
Quando nosso programa atingir um certo limite de memória e precisarmos de mais espaço na Heap, o coletor de lixo ou Garbage Collector (GC) será iniciado.
O GC irá parar todos as threads em execução, localizar todos os objetos na Heap que não estão sendo acessados pelo programa principal e excluí-los.
O GC irá então reorganizar todos os objetos deixados na Heap para liberar espaço e ajustar todos os ponteiros para esses objetos tanto na Stack quanto na Heap.
Como você pode imaginar, isso pode ser bastante custoso em termos de desempenho, então agora você pode ver por que pode ser importante prestar atenção ao que está na stack e na heap ao tentar escrever código de alto desempenho.
E estamos conversados...
"E ouvi uma grande voz do céu, que dizia: Eis aqui o tabernáculo de Deus com os
homens, pois com eles habitará, e eles serão o seu povo, e o mesmo Deus estará
com eles, e será o seu Deus."
Apocalipse 21:3
Referências: