Como um programa aloca memória? VirtualAlloc, mmap e malloc
Como um programa consegue mais memória do sistema operacional?
Em alguns casos veremos sobre malloc ou calloc, contudo, internamente ele faz algumas coisas. Vejamos:
Sempre que precisamos de mais memória, o que a grande maioria faz é usar o malloc()
Contudo, precisamos antes mesmo entender como malloc funciona.
A memória é separada entre a stack (no topo), algumas libraries (no meio) e o heap/globals/source-code (embaixo).
Esse espaço é bem grande se for uma máquina 64 bits == 17 bilhões GB de memória (mais do que temos de fato, mas que poderiamos ter).
Esse espaço, é um espaço de endereços virtuais que uma máquina pode usar para ler/escrever em conjunto com o hard drive e a CPU fará o mapeamento para a memória física. Ou seja, aqui estamos falando de memória virtual.
Retomando… entre o heap e os demais, há uma linha que define o limite que podemos alocar chamada de “Program Break”. Essa linha pode subir ou diminuir, permitindo alocarmos mais memória dinamicamente com malloc. Se você tentar ler/escrever abaixo do Program Break, ok. Caso contrário, segmentation fault!
Sempre que um malloc()
é invocado ele chama uma função: brk()
que irá subir ou descer o ProgramBreak, permitindo, que o nosso programa tenha mais memória para acessar. Agora, em alguns casos como alocar 5mb ou mais, uma outra função é chamada: o mmap()
.
mmap() é onde a mágica acontece (seu equivalente ao Windows é o
VirtualAlloc
).
mmap()
é semelhante ao brk()
, ele irá solicitar ao kernel mais memória no espaço de endereços para nós. Mas ele faz mais do que aumentar e diminuir o ProgramBreak, ele também permite definir regras de como será acessado aqueles espaços de endereços como privado, read-only, etc. Também podemos especificar o tamanho (quantas páginas vamos alocar).
Também podemos alocar arquivos em memória com os dois últimos parâmetros do mmap()
. Outro detalhe é que podemos especificar um ponto de endereço base (baseAddress) para alocar nossos dados.
Nota: O espaço virtual de endereços são definidos em páginas de 4096 bytes cada. Logo, mesmo que solicitamos tamanhos diferentes de 4k, ele irá nos fornecer páginas que caibam 4k.
Resumindo, é assim que alocadores de memórias como malloc()
funcionam. Eles solicitam espaços de endereços ao kernel que são espaços paginados em 4k e podem subir ou baixar o ProgramBreak. Contudo, o mmap()
, diferente do malloc()
, permite especificar um endereço base para gravar nossos dados e mais privilégios de acesso aos endereços.
De fato, seria difícil construir nosso próprio alocador de memória pois teriamos que trabalhar com o brk()
. A alternativa quando precisamos de um grande bloco de memória, semelhante ao que vamos usar no jogo, seria trabalhar com alocação virtual mmap()
. Ele pode fazer o trabalho melhor do que malloc porque o nosso próprio alocador de memória poderá coexistir com o alocador do sistema sem problemas e teremos controle sobre esse alocar e seus endereços.