Quando executamos um aplicativo no Windows, há três áreas na memória em que os dados são armazenados: memória global, heap e stack.
Variáveis globais (seus valores / dados) são armazenadas na memória global. A memória para variáveis globais que, é chamada de “segmento de dados”, é reservada por seu aplicativo quando o programa é iniciado e permanece alocado até que seu programa termine.
Stack e heap são onde ocorre a alocação de memória dinâmica: quando você cria uma variável para uma função, quando você cria uma instância de uma classe, quando envia parâmetros para uma função e usa / passa seu valor de resultado, entre outros.
Stack
Quando você declara uma variável dentro de uma função, a memória necessária para manter a variável é alocada da stack. Uma simples declaração como “var x: Integer” em uma função faz com que a alocação da memória e sua liberação sejam implícitas na stack. A liberação ocorre quando a variável sai do escopo (isto é, quando o código sai da função), fazendo com que a memória retirada da stack seja liberada.
A memória da stack é alocada dinamicamente usando a abordagem LIFO (“last in first out“).
Nos programas Delphi, a memória da pilha é usada:
- Variáveis de rotina local (método, procedimento, função).
- Parâmetros de rotina e tipos de retorno.
- Chamadas de função da API do Windows.
- Registros (é por isso que você não precisa criar explicitamente uma instância de um tipo de registro).
Você não precisa liberar explicitamente a memória na pilha, pois a memória é automaticamente alocada , por exemplo, ao declarar uma variável local para uma função. Quando a função sai (às vezes até antes devido à otimização do compilador Delphi) a memória para a variável será automaticamente liberada.
Pense na stack como uma pilha de blocos de memória. Quando você declara / usa uma variável local, o gerenciador de memória do Delphi selecionará o bloco do topo, o usará e, quando não for mais necessário, será retornado à pilha.
Devido ao LIFO, as operações de pilha (alocação de memória) são rápidas, pois são necessárias apenas algumas operações (push, pop) para gerenciá-la.
Exceção
Contudo, há exceções: long strings, wide strings, dynamic arrays, variants, e interfaces não são alocadas em uma stack (pilha), e sim na heap (ver adiante), mesmo que declaradas como variáveis locais, fugindo à lógica. Isso porque tratam-se de tipos dinâmicos, cuja alocação do tamanho não é determinada no momento da chamada da função ou procedure, e sim com a evolução do código dentro delas.
Heap
Um heap é uma região de memória na qual a memória alocada dinamicamente é armazenada. Quando você cria uma instância de uma classe, a memória é alocada na heap.
Nos programas Delphi, a memória heap é usada:
- Ao criar uma instância de uma classe.
- Ao criar e redimensionar matrizes dinâmicas.
- Ao alocar memória explicitamente usando GetMem(), FreeMem(), New() e Dispose().
- Usando strings ANSI / wide / Unicode, variantes, interfaces (gerenciadas automaticamente pelo Delphi).
A memória heap não tem um layout bom. Ela se assemelha a uma lata de bolinhas de gude. A alocação de memória do heap é aleatória, um bloco daqui a um bloco de lá. Assim, as operações de heap são um pouco mais lentas que as da pilha.
Quando você solicita um novo bloco de memória (por exemplo, cria uma instância de uma classe), o gerenciador de memória do Delphi irá lidar com isso para você, obtendo um novo bloco de memória ou pegando um bloco já utilizado e descartado.
O Windows permite que um aplicativo 32-bits tenha até 2 GigaBytes de espaço de endereço, a maioria dos quais pode ser usada pelo heap.