Alocação de memória, em ciência da computação, consiste no processo de solicitar/utilizar memória durante o processo de execução de um programa de computador. A alocação de memória no computador pode ser dividida em dois grupos principais:
Em C, um exemplo de alocação estática é simplesmente a declaração de uma variável:
int variavel; //O tipo de dado pode ser qualquer um
pointer (indicadores de endereços de memória). É importante ressaltar que, na maioria das linguagens de programação que o gerenciamento de memória é manual, ou seja, feito pelo programador, as variáveis criadas com alocação dinâmica não são liberadas automaticamente após o fim de funções, sendo necessário liberá-las manualmente, e, por questões de segurança, é importante atribuir o "NULL" ao ponteiro criado.Em C, um exemplo de alocação dinâmica é o seguinte:
int *ponteiro;
ponteiro = (int *) malloc(sizeof(int));
//Nos padrões modernos da linguagem C, (int *) não é necessário.
Dessa forma, o ponteiro aponta para o endereço de memória contendo um espaço do tipo e tamanho da variável int.
Em C, um exemplo para limpar a memória alocada é o seguinte:
free(ponteiro);
ponteiro = NULL;
vale ressaltar que, para usar as funções malloc() e free(), é necessário incluir a biblioteca malloc.h.
A pilha e a heap são duas regiões da memória completamente distintas e com usos diferentes.
A pilha é uma região da memória organizada de forma sequencial, ou seja, o primeiro valor a entrar na pilha, é o último a sair dela. A pilha é mais rápida e eficiente que a heap pela sua organização, mas seus valores não podem mudar de tamanho (algo de 8 bits não pode mudar para 16 bits, por exemplo).
Na maioria das linguagens de programação modernas, a saída dos valores da pilha é automático e acontece quando o escopo acaba. Um exemplo em C seria:
//Não posso acessar as variáveis aqui, pois o escopo nem começou e as variáveis nem foram definidas
int main(void) {
int x = 1;
char y = 'A';
char *z = "Texto";
return 0;
}
//Também não posso acessá-las aqui, pois o escopo acabou, então elas não são mais acessíveis.
No exemplo acima, o escopo é a área delimitada pelas chaves. Cada uma dessas variáveis é uma variável na pilha, que não pode ser acessada fora do escopo em que foi definida, pois saem da pilha quando ele acaba.
A heap é outra região da memória organizada de forma não sequencial, portanto, ela não tem uma ordem exata. A vantagem da heap é: se uma variável precisar aumentar de capacidade, você pode alocar mais espaço na heap para armazenar um valor maior. Como desvantagem, ela é mais lenta de se acessar e interagir, pois não é sequencial. A alocação de memória na heap é a alocação dinâmica, explicada anteriormente.
Nas linguagens com gerenciamento de memória manual, a alocação, realocação e desalocação são completamente manuais, por isso são considerados conceitos complexos, além de que podem causar vazamentos de memória.
#include <malloc.h>
int main() {
int *X = malloc(10 * sizeof(int));
if (!X) return 1;
X = realloc(X, 20 * sizeof(int));
if (!X) return 1;
free(X);
X = NULL;
return 0;
}
O exemplo acima mostra como alocar, realocar e liberar o espaço da memória. Pode parecer simples, mas a dificuldade é tanta que há uma linguagem de baixo nível que evita o gerenciamento de memória manual: Rust. Há várias regras sobre o uso da memória da heap, tornando-o complexo e um assunto difícil de possuir maestria completa.