Cada postagem sobre alocação de memória parece explicar como mmap
é usado ou como sbrk
foi usado, sem levar em consideração como eles podem ser contextualizados com o heap.
Concluí que o heap desempenha um papel quase insignificante nas alocações de memória - na verdade, não tenho certeza do que ele faz: D, e peço que alguém me desconfunda.
Isto é o que eu entendo:
1) Quando a memória é maloced, o final do segmento de dados não inicializado, o BSS, é expandido. Essa expansão (que move um endereço x
para, digamos, x-n
) ocorre como resultado de uma chamada para sbrk
. Neste modelo, a memória é alocada nos n
bytes (assumindo que cada endereço está em correspondência com um byte) que sbrk
diminui a posição do cabeçalho do segmento BSS. Este modelo já está obsoleto. Alguns definem o heap como sendo o espaço que é o agregado de todas essas expansões. Outros não -- no último caso, o que o heap faz?
2) Nos esquemas modernos de alocação de memória, existe um heap (por que motivo, novamente, não tenho certeza). Para alocar memória, malloc
usa internamente mmap
para armazenar dados em regiões de memória que são uma coleção de páginas. Essas regiões de memória são independentes do heap.
TLDR:
Para sistemas antigos: Se as alocações de memória forem armazenadas no espaço de endereço obtido após aumentar o deslocamento do BSS final, um heap serve a algum propósito?
Para sistemas mais novos: Admitindo que o mmap seja usado principalmente para alocações de memória, a que propósito o heap serve?
Em ambos os casos, o heap realmente faz algo útil?
mmap
esbrk
são as chamadas de sistema que o kernel fornece para alocar espaço de endereço para processos. Essas chamadas alteram o mapeamento de endereços virtuais para quadros de página físicos. Endereçar a memória fora dos limites de endereço desses mapeamentos é estritamente proibido e resulta em uma falha de segmentação. Esta é a interface de baixo nível que o kernel fornece a um processo, e a área de memória que termina com obrk
endereço é comumente chamada de heap.O kernel não sabe nada sobre
malloc
oufree
, essas são funções de biblioteca em libc. Libc mantém estruturas de dados e registra quais áreas de memória estão livres do ponto de vista da alocação de memória, por exemplo como o arquivo . Uma chamada paramalloc
não resulta necessariamente em uma chamada parasbrk
oummap
(dependendo de como Libc implementa a alocação dinâmica de memória) para expandir os mapeamentos, se uma chamada paramalloc
puder ser atendida reutilizando áreas de memória previamente liberadas."A pilha" é uma ideia de alto nível, não uma implementação de baixo nível. Em C, o heap é qualquer pool de memória
malloc()
usado para fornecer alocações.Aqui está uma implementação simples e divertida do alocador de memória:
Este é um alocador terrível, mas para o tipo certo de programa e se seu sistema e compilador perdoam coisas como alinhamento de memória , isso meio que funciona. Seu heap é o
heap[]
array e ele o constrói em tempo de compilação usando uma declaração de array, em vez de montar um comsbrk()
oummap()
.Um alocador "real" funciona da mesma maneira. Quando
malloc()
é chamado, ele pega uma pequena parte de seu pool de memória (seu heap) e o reserva para essa alocação. Há duas diferenças importantes:free()
uma alocação para poder usá-la novamente mais tarde.sbrk()
oummap()
) quando todos os blocos existentes estiverem cheios.