Existem alguns limites que se aplicam ao segmento mmap
e ao segmento de heap. RLIMIT_AS
determina o espaço de endereço disponível, em geral; Isso abrange todas as alocações de memória que um programa pode fazer. RLIMIT_DATA
determina o tamanho máximo do segmento de dados.
O kernel verifica a expansão de pilha, mmap
e brk
(alocação de heap) contra esses limites. Ele também verifica as alocações contra segmentos potencialmente conflitantes, para que os segmentos nunca acabem se sobrescrevendo (veja, por exemplo, as verificações realizadas para alocação de heap com brk
). Se uma alocação for impossível, o programa é “informado” conforme apropriado: a biblioteca C retorna um erro ENOMEM
para brk
, o kernel mata o programa com um SIGSEGV
se a pilha não puder ser expandida ...
Como o segmento de memória compartilhada (estritamente falando da perspectiva do kernel, área de memória virtual) cresce depende do layout da memória, que pode variar de um processo para outro. Na maioria das arquiteturas, os mapas de memória “herdados” resultam em alocação de baixo para cima, a partir de TASK_UNMAPPED_BASE
; mapas de memória não herdados resultam em alocação top-down. Veja arch_pick_mmap_layout()
e mmap_is_legacy()
na arquitetura x86 para um exemplo. Você pode alternar para o mapa de memória herdada usando setarch
' -L
flag (veja abaixo um exemplo).
Na prática, você pode ver como o segmento cresce observando /proc/$$/maps
e verificando os endereços das bibliotecas compartilhadas carregadas (se houver), v. sua ordem de carregamento. O vinculador dinâmico é sempre carregado primeiro; se tiver um endereço mais baixo do que outras bibliotecas, a alocação será de baixo para cima, caso contrário, será de cima para baixo. Compare a saída de cat /proc/self/maps
e setarch x86_64 -L cat /proc/self/maps
em um sistema x86 de 64 bits.