[Linux] Resumo da alocação de memória-malloc, brk, mmap

 

Original: https://blog.csdn.net/gfgdsg/article/details/42709943

http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/

http://blog.sina.com.cn/s/blog_7c60861501015vkk.html

Existem vários conceitos-chave no gerenciamento de memória virtual do Linux: 

1. Cada processo tem um espaço de endereço virtual independente,
e o endereço virtual acessado pelo processo não é um endereço físico real;  2. O endereço virtual pode passar pela tabela de página em cada processo (no espaço de endereço virtual do kernel de cada processo ) e O endereço físico é mapeado para obter o endereço físico real; 
3. Se o endereço físico correspondente ao endereço virtual não estiver na memória física, uma interrupção de falha de página é gerada, o endereço físico é realmente alocado e a tabela de página do processo é atualizado ao mesmo tempo; se a memória física se esgotar neste momento, de acordo com o algoritmo de substituição de memória, algumas páginas são eliminadas para o disco físico. 

   
Com base no entendimento acima, a seguinte análise é feita:
1. Como o espaço de endereçamento virtual do Linux é distribuído?
O Linux usa espaço de endereço virtual, o que aumenta muito o espaço de endereçamento do processo. Do endereço baixo ao endereço alto, eles são
1. Segmento somente leitura: esta parte do espaço só pode ser lida, mas não escrita; (incluindo: código segmento, segmento rodata (C strings constantes e constantes definidas por #define))
2. Segmento de dados: o espaço para salvar variáveis ​​globais e variáveis ​​estáticas; 
3. Heap: geralmente é chamado de memória dinâmica, e a maior parte de malloc / new vem de isto. A posição do topo da pilha pode ser ajustada dinamicamente pelas funções brk e sbrk. 
4. Área de mapeamento de arquivo: como biblioteca dinâmica, memória compartilhada e outra memória que mapeia o espaço físico, geralmente é o espaço de endereço virtual alocado pela função mmap. 
5. Pilha: usado para manter o espaço de contexto para chamadas de função, geralmente 8M, que pode ser visualizado por meio de ulimit -s. 
6. Espaço virtual do kernel: uma área de memória invisível ao código do usuário, gerenciada pelo kernel (a tabela de páginas é armazenada no espaço virtual do kernel).

A figura a seguir é uma distribuição de espaço de endereço virtual típica de um sistema de 32 bits (de "Conhecimento aprofundado de sistemas de computador").

 

O sistema de 32 bits tem espaço de endereço 4G ::

      Entre eles, 0x08048000 ~ 0xbfffffff é o espaço do usuário e 0xc0000000 ~ 0xffffffff é o espaço do kernel, incluindo código e dados do kernel e estruturas de dados relacionadas ao processo (como tabelas de página, pilhas de kernel), etc. Além disso, % esp executa o topo da pilha e muda para a direção do endereço baixo; a função brk / sbrk controla o topo do heap _edata para mudar para a direção do endereço alto .


Qual é o resultado para sistemas de 64 bits? Um sistema de 64 bits tem um espaço de endereço de 2 ^ 64?  
Na verdade, a divisão do espaço de endereço virtual dos sistemas de 64 bits mudou: 
1. O tamanho do espaço de endereço não é 2 ^ 32, nem 2 ^ 64, mas geralmente 2 ^ 48. Como não há necessidade de um espaço de endereçamento tão grande quanto 2 ^ 64, muito espaço só levará ao desperdício de recursos. O Linux de 64 bits geralmente usa 48 bits para representar o espaço de endereço virtual e 40 bits para representar o endereço físico.
Isso pode ser visto em / proc / cpuinfo. 
Tamanhos de endereço: 40 bits físicos, 48 ​​bits virtuais 
2. Entre eles, 0x0000000000000000 ~ 0x00007fffffffffff representa o espaço do usuário, 0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF representa o espaço do kernel, fornecendo um total de 256 TB (2 ^ 48) de espaço de endereçamento.
A característica desses dois intervalos é que o 47º bit é igual a 48 ~ 63 bits. Se esses bits forem 0, isso significa espaço do usuário, caso contrário, significa espaço do kernel. 
3. O espaço do usuário ainda é um segmento somente leitura, segmento de dados, heap, área de mapeamento de arquivo e pilha de endereço baixo para endereço alto ;

 

2. Como malloc e free alocam e liberam memória?

Como verificar o número de interrupções de falha de página em um processo ?

         Use o comando do programa ps -o majflt, minflt -C para visualizar.

          majflt significa falha grave, o nome chinês é um grande erro, minflt significa falha menor e o nome chinês é falha pequena .

          Esses dois valores indicam o número de falhas de página que ocorreram desde o início de um processo.

Depois que a interrupção de falha de página foi emitida, quais operações foram realizadas?

Quando ocorre uma interrupção de falha de página em um processo, o processo cairá no estado do kernel e executará as seguintes operações
1. Verifique se o endereço virtual a ser acessado é legal 
2. Encontre / aloque uma página física 
3. Preencha a página física conteúdo (leia o disco ou defina como 0 diretamente ou não faça nada) 
4.
Estabeleça a relação de mapeamento (endereço virtual para endereço físico) e 
execute novamente a instrução que causou a interrupção da falha de página. 
Se o disco precisar ser lido etapa 3, então esta interrupção de falha de página é majflt, caso contrário, é minflt. 

Princípio de alocação de memória

Do ponto de vista do sistema operacional, há duas maneiras de um processo alocar memória, que são concluídas por duas chamadas de sistema: brk e mmap (sem considerar a memória compartilhada).

1. brk empurra o ponteiro de endereço mais alto _edata do segmento de dados (.data) para um endereço mais alto;

2. mmap é encontrar uma memória virtual livre no espaço de endereço virtual do processo (entre o heap e a pilha, chamado de área de mapeamento de arquivo) .

     Ambos os métodos alocam memória virtual e nenhuma memória física é alocada . Ao acessar o espaço de endereço virtual alocado pela primeira vez, ocorre uma interrupção de falha de página e o sistema operacional é responsável por alocar a memória física e, em seguida, estabelecer a relação de mapeamento entre a memória virtual e a memória física.


Na biblioteca C padrão, as funções malloc / free são fornecidas para alocar e liberar memória.A camada inferior dessas duas funções é implementada por chamadas de sistema, como brk, mmap e munmap.


Aqui está um exemplo para ilustrar o princípio de alocação de memória:

Caso 1: se malloc tiver menos de 128k de memória, use brk para alocar memória e enviar _edata para um endereço superior (apenas o espaço virtual é alocado, não correspondendo à memória física (portanto, não é inicializado), e ocorre a falha de página do kernel quando os dados são lidos / gravados pela primeira vez. Após a interrupção, o kernel aloca a memória física correspondente e, em seguida, o espaço de endereço virtual estabelece a relação de mapeamento), conforme mostrado na figura a seguir:

 

 

1. Quando o processo é iniciado, o layout inicial de seu espaço de memória (virtual) é mostrado na Figura 1.

      Entre eles, o arquivo mapeado pela memória mmap está no meio do heap e da pilha (por exemplo, libc-2.2.93.so, outros arquivos de dados, etc.) Para simplificar, o arquivo mapeado pela memória é omitido.

      O ponteiro _edata (definido em glibc) aponta para o endereço mais alto do segmento de dados. 
2. Depois que o
processo chama A = malloc (30K), o espaço de memória é mostrado na Figura 2:

      A função malloc chamará a chamada de sistema brk, enviará o ponteiro _edata para um endereço alto em 30K e completará a alocação de memória virtual.

      Você pode perguntar:  Basta colocar _edata + 30K para completar a alocação de memória?

      O fato é que _edata + 30K apenas completa a alocação de endereços virtuais. Ainda não há uma página física correspondente à memória de A. Quando o processo lê e grava a memória de A pela primeira vez, ocorre uma interrupção de falha de página. desta vez, o kernel aloca a página física correspondente ao bloco A de memória. Em outras palavras, se o conteúdo de A for alocado por malloc e nunca acessado, a página física correspondente a A não será alocada. 
3. Depois que o
processo chama B = malloc (40K), o espaço de memória é mostrado na Figura 3.

 

Caso 2: se malloc for maior que 128k de memória, use mmap para alocar memória, encontre uma alocação de memória livre entre o heap e a pilha (correspondendo à memória independente e inicializado em 0), conforme mostrado na figura a seguir:

 

 

4. Depois que o processo chama C = malloc (200K), o espaço de memória é mostrado na Figura 4:

      Por padrão, a função malloc aloca memória. Se a memória solicitada for maior que 128 K (ajustada pela opção M_MMAP_THRESHOLD), em vez de empurrar o ponteiro _edata, ela usa a chamada de sistema mmap para alocar um pedaço de memória virtual do meio de a pilha e a pilha.

      As principais razões para fazer isso são:

      A memória alocada por brk não pode ser liberada até que a memória de endereço alto seja liberada (por exemplo, é impossível que A seja liberado antes que B seja liberado. Esta é a causa da fragmentação da memória. Quando apertar, veja abaixo), enquanto o a memória alocada por mmap pode ser separada e liberada.

      Claro, existem outras vantagens e desvantagens. Indo além, os alunos interessados ​​podem ir para o código malloc na glibc. 
5. Depois que o processo chama D = malloc (100K), o espaço de memória é mostrado na Figura 5.
6. Depois que o processo chama free (C), a memória virtual e a memória física correspondente a C são liberadas juntas.

 

 

7. Após o processo ligar gratuitamente (B), conforme mostrado na Figura 7:

        A memória virtual e a memória física correspondente a B não são liberadas porque há apenas um ponteiro _edata. Se você empurrar de volta, o que acontece com a memória de D ?

É claro que essa memória B pode ser reutilizada, se a solicitação desta vez for novamente 40K, então o malloc B provavelmente colocará essa memória de volta
8. Após o processo chama gratuitamente (D), conforme mostrado na Figura 8:

        B e D estão conectados para se tornarem uma memória livre de 140K.

9. Por padrão:

       Quando a memória livre do espaço de endereço mais alto excede 128K (ajustável pela opção M_TRIM_THRESHOLD), uma operação de compactação de memória (trim) é executada. Quando a última etapa estava livre, descobriu-se que a memória livre no endereço mais alto ultrapassava 128K, então a memória foi compactada e tornou-se conforme mostrado na Figura 9.

 

3. Como o brk e o sbrk da memória no heap não podem ser liberados diretamente, por que não usar o mmap para alocar todos eles e o munmap para liberá-los diretamente? 

 

 

        Uma vez que os fragmentos no heap não podem ser liberados diretamente, levando ao problema suspeito de "vazamento de memória", por que nem todos os malloc usam o mmap para obtê-lo (a memória alocada pelo mmap pode ser liberada pelo munmap para obter a liberação real)? Em vez disso, use mmap apenas para grandes blocos de memória maiores que 128k? 

        Na verdade, as interfaces sbrk / mmap / munmap para o processo de solicitação e liberação do espaço de endereço do SO são todas chamadas de sistema e chamadas de sistema frequentes consomem recursos do sistema. Além disso, depois que a memória solicitada pelo mmap for munmap, a reaplicação irá gerar mais interrupções de falha de página. Por exemplo, quando o mmap é usado para alocar 1M de espaço, um grande número de interrupções de falha de página (1M / 4K vezes) é gerado na primeira chamada. Quando 1M de espaço é alocado novamente após o munmap, um grande número de interrupções de falha de página será gerado novamente. A interrupção de falha de página é um comportamento do kernel, que causará alto consumo de CPU no modo kernel. Além disso, se o mmap for usado para alocar pouca memória, isso resultará em mais fragmentação do espaço de endereço e maior carga de gerenciamento no kernel.
        Ao mesmo tempo, o heap é um espaço contínuo e, uma vez que os fragmentos no heap não são retornados ao sistema operacional, se os fragmentos forem reutilizáveis, acessar a memória novamente provavelmente não gerará chamadas de sistema e interrupções de falha de página, o que irá reduz bastante o consumo de CPU . Portanto, na implementação malloc de glibc, as diferenças e vantagens e desvantagens do comportamento de sbrk e mmap são totalmente consideradas. Por padrão, um grande bloco de memória (128k) é alocado para obter o espaço de endereço usando mmap, que também pode ser modificado por mallopt (M_MMAP_THRESHOLD, <SIZE>) Este valor crítico.

 

4. Como verificar as informações de interrupção de falha de página do processo? 
Você pode usar o seguinte comando para visualizar as informações de interrupção de falha de página 
ps -o majflt, minflt -C <program_name> 
ps -o majflt, minflt -p <pid> 
onde:

          majflt significa falha grave, o nome chinês é um grande erro,

        minflt significa falha secundária e o nome chinês é falha secundária.

          Esses dois valores indicam o número de falhas de página que ocorreram desde o início de um processo.

Depois que a interrupção de falha de página foi emitida, quais operações foram realizadas?

Quando ocorre uma interrupção de falha de página em um processo, o processo cairá no estado do kernel e executará as seguintes operações: 
1. Verifique se o endereço virtual a ser acessado é legal 
2. Encontre / aloque uma página física 
3. Preencha a página física conteúdo (leia o disco ou defina como 0 diretamente ou não faça nada) 
4. Estabeleça a relação de mapeamento (endereço virtual para endereço físico) e 
execute novamente a instrução que causou a interrupção da falha de página. 
Se o disco precisar ser lido etapa 3, então esta interrupção de falha de página é majflt, caso contrário, é minflt.

Mecanismo de alocação de memória do Linux: https://blog.csdn.net/gfgdsg/article/details/42709943 (Como malloc e free alocam e liberam memória?)

                                 https://www.cnblogs.com/wangliangblog/p/9109384.html

Cinco, método de alocação de memória em linguagem C e malloc

  
Linguagem C e método de alocação de memória
(1) Alocar da área de armazenamento estático. A memória é alocada quando o programa é compilado, e essa memória existe durante todo o período de execução do programa. Por exemplo, variáveis ​​globais, variáveis ​​estáticas.
(2) Crie na pilha. Quando a função é executada, as unidades de armazenamento das variáveis ​​locais na função podem ser criadas na pilha e essas unidades de armazenamento são liberadas automaticamente quando a função é executada. A operação de alocação de memória da pilha
é incorporada ao conjunto de instruções do processador e é muito eficiente, mas a capacidade de memória alocada é limitada.
(3) Alocação do heap, também conhecida como alocação de memória dinâmica. Quando o programa estiver rodando, use malloc ou new para solicitar qualquer quantidade de memória, e o programador é responsável por quando usar free ou delete para liberar a memória. O tempo de vida da memória dinâmica é determinado por nós, é muito flexível de usar, mas o problema também é o mais
     

      As funções da linguagem C relacionadas à aplicação de memória incluem principalmente aloc, calloc, malloc, free, realloc, sbrk, etc. Dentre elas, aloc se aplica à memória da pilha, portanto não há necessidade de liberá-la. está localizado na pilha e a memória não foi inicializada. Conteúdo, então basicamente após malloc, chame a função memset para inicializar esta parte do espaço de memória. Calloc irá inicializar esta parte da memória e configurá-la para 0. E realloc irá ajustar o tamanho da memória solicitada por malloc. A memória solicitada eventualmente será necessária Ela é liberada através da função free. E sbrk aumenta o tamanho do segmento de dados;
       malloc / calloc / free são basicamente implementados pela biblioteca de funções C, e não têm nada a ver com o sistema operacional. A biblioteca de funções C usa uma certa estrutura para economizar a quantidade de memória disponível no momento. Se o tamanho do programa malloc exceder o espaço reservado na biblioteca, a chamada de sistema brk será chamada primeiro para aumentar o espaço disponível e, em seguida, o espaço será alocado. Quando livre, a memória liberada não é imediatamente devolvida ao sistema operacional, mas é retida internamente na estrutura. Você pode fazer uma analogia: o brk é semelhante a um aplicativo de atacado único de grande memória para o sistema operacional, enquanto funções como malloc são semelhantes às de varejo e atendem aos requisitos de tempo de execução do programa. Este mecanismo é semelhante ao armazenamento em buffer.
Use este mecanismo Motivo: as chamadas do sistema não podem oferecer suporte à alocação de memória de qualquer tamanho (algumas chamadas do sistema apenas suporta aplicativos de memória de tamanhos fixos e múltiplos dos mesmos. Neste caso, a alocação de pouca memória causará desperdício; as chamadas do sistema são caras para solicitar memória e envolvem os usuários. Conversão entre estado e estado central.
Ambos malloc () e calloc () podem ser usado para alocar espaço de memória dinâmica, mas há uma ligeira diferença entre os dois.

      No sistema Linux, quando um programa é carregado na memória, o kernel cria um segmento de código, um segmento de dados e um segmento de pilha para o espaço de endereço do processo do usuário, e a área livre entre o segmento de dados e o segmento de pilha é usada para alocação de memória dinâmica.
      As variáveis ​​de membro start_code e end_code na estrutura de dados do kernel mm_struct são os endereços inicial e final do segmento do código do processo, start_data e end_data são os endereços inicial e final do segmento de dados do processo, start_stack é o endereço inicial do segmento da pilha do processo, e start_brk é a memória dinâmica do processo O endereço inicial da alocação (o endereço inicial do heap) e um brk (o último endereço atual do heap), que é o endereço final atual da alocação de memória dinâmica.
A função básica da alocação dinâmica de memória na linguagem C é malloc (), e a implementação básica no Linux é por meio da chamada de sistema brk do kernel. brk () é uma chamada de sistema muito simples, que simplesmente muda o valor da variável membro brk da estrutura mm_struct.
      A chamada de sistema mmap implementa uma função de alocação de memória dinâmica mais útil, que pode mapear todo ou parte de um arquivo em disco para o espaço do usuário, e o processo de leitura e gravação de arquivos torna-se uma operação de leitura e gravação de memória. A função do_mmap_pgoff () no arquivo linux / mm / mmap.c é o núcleo da implementação da chamada do sistema mmap. O código de do_mmap_pgoff () apenas cria uma nova estrutura vm_area_struct e atribui os parâmetros da estrutura do arquivo à sua variável membro m_file, mas não carrega realmente o conteúdo do arquivo na memória.
Uma das idéias básicas do gerenciamento de memória do Linux é estabelecer um mapeamento físico de um endereço apenas quando ele for realmente acessado.

Acho que você gosta

Origin blog.csdn.net/bandaoyu/article/details/113622404
Recomendado
Clasificación