Análise dos princípios subjacentes do ptmalloc

Índice

I. Visão geral

2. Compreensão básica

2.1 Layout de memória padrão de processos de 32 bits

2.2 brk & sbrk & mmap

3. Gerenciamento de memória

2.1 Estrutura

2.1.1 main_arena dada non_main_arena

2.1.2 malloc_chunk

2.1.3 Caixas de listas gratuitas

2.1.4 Inicialização

2.2 Alocação e liberação de memória

2.3 Precauções de uso

3. Análise comparativa dos mecanismos de implementação de ptmalloc, tcmalloc e jemalloc


I. Visão geral

ptmalloc é o gerenciador de memória padrão da biblioteca GNU C de código aberto (glibc).Atualmente, a maioria dos programas de servidor Linux usa a série de funções malloc/free fornecida por ptmalloc, e seu desempenho é muito pior do que o jemalloc do Meta e o tcmalloc do Google.

O programa do servidor chama a função malloc/free fornecida por ptmalloc para solicitar e liberar memória. ptmalloc fornece gerenciamento centralizado de memória para obter o máximo possível:

  • É mais eficiente para os usuários solicitarem e liberarem memória, evitando a simultaneidade e o bloqueio de aplicativos de memória multithread.

  • Busque um equilíbrio entre o uso de memória e o consumo de desempenho malloc/free durante a interação com o sistema operacional, reduza a fragmentação de memória e chame funções de chamada do sistema com pouca frequência

A fim de melhorar a eficiência da função de alocação de memória malloc, ptmalloc solicitará um pedaço de memória do sistema operacional antecipadamente para uso dos usuários, e ptmalloc gerenciará a memória usada e livre; quando o usuário precisar liberar a memória livre, ptmalloc irá reciclar a memória. A memória é gerenciada e é decidido se deve ser reciclada para o sistema operacional de acordo com a situação real ( conectividade do pool de memória )

2. Compreensão básica

2.1 Layout de memória padrão de processos de 32 bits

A pilha se expande de cima para baixo, o heap se expande de baixo para cima e a área de mapeamento mmap se expande de cima para baixo. A área de mapeamento mmap e o heap são relativamente expandidos até que a área restante no espaço de endereço virtual se esgote

2.2 brk & sbrk & mmap

int brk(const void *addr)
void* sbrk(intptr_t incr)
  • A função de ambos é expandir o limite superior do heap
  • O parâmetro de brk() é definido como o novo endereço do limite superior de brk. Ele retorna 1 em caso de sucesso e 0 em caso de falha.
  • O parâmetro de sbrk() é o tamanho da memória solicitada e retorna o endereço do novo limite superior brk do heap.
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
int munmap(void& addr, size_t length)
  • O primeiro uso do mmap é mapear esse arquivo de disco para a memória.
  • O segundo uso do mmap é o mapeamento anônimo. Este arquivo de disco não é mapeado, mas um pedaço de memória é solicitado da área de mapeamento. Malloc usa o segundo uso.
  • munmap é usado para liberar memória

3. Gerenciamento de memória

2.1 Estrutura

Para resolver o problema de contenção de bloqueio multithread, a alocação de memória é dividida em área de alocação principal (main_area) e área de alocação não principal (no_main_area). Ao mesmo tempo, para facilitar o gerenciamento de memória, a memória pré-aplicada é dividida em muitos pedaços (pedaços) usando o método de marcação de limites; no alocador de memória ptmalloc, malloc_chunk é a unidade organizacional básica, usada para gerenciar (descrever) diferentes tipos de pedaços, funções e tamanhos Pedaços semelhantes são conectados em série para formar uma lista vinculada, chamada bin.

2.1.1 main_arena dada non_main_arena

No alocador de memória, para resolver o problema de contenção de bloqueio multithread, ele é dividido na área de alocação principal main_area (a essência da área de alocação é o pool de memória, que gerencia pedaços) e a área de alocação não principal no_main_area

  • A área de alocação principal e a área de alocação não primária formam uma lista circular vinculada para gestão

  • Cada área de alocação usa um bloqueio mutex para evitar que threads acessem a área de alocação.

  • Cada processo possui apenas uma área de alocação primária e são permitidas múltiplas áreas de alocação não primária.

  • ​ ptmalloc aumenta dinamicamente o tamanho da área de alocação de acordo com a chamada do sistema para a área de alocação. Uma vez que o número de áreas de alocação aumenta, ele não diminuirá.

  • A área de alocação principal pode ser alocada usando brk() e mmap(), enquanto a área de alocação não principal só pode usar mmap() para mapear blocos de memória.

  • Ao solicitar memória pequena, muitos fragmentos de memória serão gerados. O ptmalloc também precisa bloquear a área de alocação ao classificá-la.

Quando um thread precisa usar malloc para alocar memória, ele primeiro verifica se existe uma área de alocação na variável privada do thread e, se existir, tentará bloqueá-la. Se o bloqueio for bem-sucedido, a memória será alocada usando a área de alocação; se falhar, a lista vinculada circular será percorrida para obter uma área de alocação desbloqueada. Se não houver área de alocação desbloqueada em toda a lista vinculada, uma nova área de alocação será aberta, adicionada à lista vinculada circular global e bloqueada, e então a área de alocação será usada para alocação. Quando esta memória for liberada, o bloqueio da área de alocação onde está localizado o bloco de memória a ser liberado também será adquirido primeiro. Se outros threads estiverem usando a área de alocação, você deverá esperar que outros threads liberem o bloqueio mutex da área de alocação antes que a memória possa ser liberada.

Perceber:

  • Embora a área de alocação não primária seja alocada por mmap(), ela não tem nada a ver com o uso direto de mmap() para alocação maior que 128K. Memória maior que 128K é alocada usando mmap() e retornada ao sistema diretamente usando ummap() após o uso.

  • Cada thread primeiro obterá uma área no malloc e usará o pool de memória da área para alocar sua própria memória.Há uma relação de competição.

  • Para evitar concorrência, você pode usar a estratégia de armazenamento local de thread, thead cache (tc em tcmalloc significa exatamente isso)

2.1.2 malloc_chunk

ptmalloc gerencia uniformemente os pedaços livres nas áreas de mapeamento heap e mmap.Quando o usuário faz uma solicitação de alocação, ele primeiro tenta encontrar e dividir os pedaços livres,evitando assim chamadas frequentes do sistema e reduzindo o custo de alocação de memória. Para melhor gerenciar e encontrar pedaços livres, as informações de controle necessárias são adicionadas antes e depois do espaço pré-alocado.

  • prev_size: Se o bloco anterior for gratuito, este campo indica o tamanho do bloco anterior; se não for gratuito, este campo não tem sentido (saiba o endereço do bloco atual, subtraia prev_size e você obterá o endereço do bloco anterior. prev_size é usado principalmente para mesclar partes livres adjacentes relacionadas)
  • size: o tamanho do pedaço atual e registra os seguintes outros atributos
    • O pedaço anterior está em uso (P = 1)
    • O pedaço atual é a alocação de área de mapeamento mmap (M = 1) ou alocação de área de heap (M = 0)
    • O pedaço atual pertence à área de alocação não primária (A = 0) ou à área de alocação não primária (A = 1)
  • fd e bk: só existirão quando o pedaço estiver livre. Sua função é adicionar o bloco de pedaço livre correspondente à lista de blocos de pedaço livre para gerenciamento unificado. Se o bloco de pedaço for alocado para o aplicativo, esses dois ponteiros serão inúteis , portanto esta área também é usada como espaço do aplicativo.
  • fd_nextsize & bk_nextsize: O pedaço atual existe em caixas grandes. Os pedaços livres em caixas grandes são classificados por tamanho. Se houver vários pedaços do mesmo tamanho, adicionar esses dois campos pode acelerar a travessia dos pedaços livres e encontrar os pedaços livres que atendem às necessidades. , fd_nextsize aponta para o próximo primeiro pedaço livre que é maior que o pedaço atual e bk_nextsize aponta para o primeiro pedaço livre anterior que é menor que o pedaço atual. Se o bloco chunk for alocado para o aplicativo, esses dois ponteiros serão inúteis, portanto, essa área também será usada como espaço do aplicativo.
//ptmalloc源码中定义结构体malloc_chunk来描述这些块
struct malloc_chunk
{
  INTERNAL_SIZE_T      prev_size;    /* Size of previous chunk (if free).  */  
  INTERNAL_SIZE_T      size;         /* Size in bytes, including overhead. */  
  
  struct malloc_chunk* fd;           /* double links -- used only if free. */  
  struct malloc_chunk* bk;  
  
  /* Only used for large blocks: pointer to next larger size.  */  
  struct malloc_chunk* fd_nextsize;      /* double links -- used only if free. */  
  struct malloc_chunk* bk_nextsize; 
};

pedaço em uso

  • O ponteiro do bloco aponta para o endereço onde o bloco começa; o ponteiro mem aponta para o endereço onde o bloco de memória do usuário começa.
  • ​ Quando P = 0, significa que o bloco anterior está livre e prev_size é válido.
  • ​ Quando P=1, significa que o pedaço anterior está sendo usado e prev_size é inválido. p é usado principalmente para mesclar blocos de memória. O primeiro bloco alocado por ptmalloc sempre define p como 1 para evitar que o programa faça referência a uma área inexistente
  • ​ M=1 é alocação de área de mapeamento mmap; M=0 é alocação de área de heap
  • ​ A=0 é alocado para a área de alocação principal; A=1 é alocado para a área de alocação não primária.

pedaço grátis

 Quando o pedaço está ocioso, o estado M não existe, apenas o estado AP. Porque M indica se a memória é alocada por brk ou mmap, e a memória alocada por mmap é mapeada diretamente quando está livre e não será colocada na lista vinculada livre. Quatro ponteiros são armazenados no que era originalmente a área de dados do usuário. O ponteiro fd aponta para o próximo pedaço livre e bk aponta para o pedaço livre anterior. Malloc usa esses dois ponteiros para conectar pedaços de tamanho semelhante em uma lista duplamente vinculada.

Reutilização de espaço em pedaços

  • Para minimizar o espaço ocupado pelos pedaços, o ptmalloc utiliza a reutilização de espaço. Em diferentes estados de um pedaço, certas áreas têm significados diferentes para conseguir a reutilização.
  • Quando ocioso, um pedaço requer pelo menos 2 espaços size_t e 2 espaços do tamanho de um ponteiro para armazenar prev_size, size, fd e bk, que tem 16 bytes
  • Quando um pedaço está em uso, o campo prev_size do próximo pedaço é definitivamente inválido, portanto esse espaço também pode ser usado pelo pedaço atual.

Portanto, a fórmula de cálculo para o tamanho de um pedaço em uso é: in_use_size = (solicitação do usuário + 8 - 4)

8 bytes são adicionados para armazenar prev_size e size, mas como 4 bytes são emprestados do próximo pedaço, 4 são subtraídos. Como o pedaço livre e o pedaço em uso usam o mesmo espaço, o valor máximo deve ser considerado como o espaço alocado real, ou seja, o espaço alocado final é chunk_size = max(in_use_size,16)

Pedaço especial

pedaço superior

  • O pedaço superior é equivalente à memória livre no topo da área de alocação.Quando as caixas não puderem atender aos requisitos de alocação de memória, ela será alocada no pedaço superior.
  • Quando o tamanho do pedaço superior for maior que o tamanho solicitado pelo usuário, o pedaço superior será dividido em duas partes, o pedaço do usuário e o pedaço restante (tamanho restante). Entre eles, o pedaço restante torna-se o novo pedaço superior.
  • Quando o tamanho do pedaço superior é menor que o tamanho solicitado pelo usuário, o pedaço superior é expandido por meio da chamada de sistema sbrk (main arena) ou mmap (thread arena).

pedaço mapeado

  • Quando a memória alocada é muito grande (maior que o limite de alocação, o padrão é 128k) e precisa ser mapeada por mmap, ela será colocada no pedaço mmaped.Quando a memória no pedaço mmaped for liberada, ela será retornada diretamente para o sistema operacional (sinalizador M no bloco) para 1)

último pedaço restante

  • O último pedaço restante é um pedaço especial, assim como o pedaço superior e o pedaço mapeado. Este pedaço não será encontrado em nenhuma caixa. Quando um pedaço pequeno precisa ser alocado, um pedaço adequado não pode ser encontrado nas caixas pequenas. Se o tamanho do último pedaço restante for maior que o tamanho do pedaço pequeno necessário, o último pedaço restante será dividido em dois pedaços, um dos quais será retornado ao usuário e o outro pedaço se tornará o novo último pedaço restante.

2.1.3 Caixas de listas gratuitas

Quando o usuário libera memória, o ptmalloc não retornará imediatamente a memória ao sistema operacional. Em vez disso, ela será gerenciada pelas caixas de lista vinculada livre do ptmalloc. Na próxima vez que o processo precisar de memória malloc, o ptmalloc encontrará um bloco de memória adequado no compartimentos livres. Aloque aos usuários para evitar chamadas frequentes do sistema e reduzir a sobrecarga de alocação de memória.

ptmalloc conecta pedaços de tamanhos semelhantes usando uma lista duplamente vinculada. Essa lista vinculada é chamada de bin. ptmalloc mantém um total de 128 bins, e cada bin mantém pedaços de listas duplamente vinculadas de tamanhos semelhantes. Com base no tamanho do bloco, os seguintes compartimentos estão disponíveis:

 Nota: Em plataformas de 32 bits, bin[0] e bin[127] não existem. bin[1] são caixas não classificadas, bin[2]~bin[126] são caixas classificadas

lixeira não classificada

  • A fila de caixas não classificadas está localizada no segundo (subscrito 1) do array de caixas.É um buffer de caixas para acelerar a alocação.
  • Quando a memória liberada pelo usuário é maior que max_fast ou os pedaços após a fusão dos compartimentos rápidos entrarão primeiro nos compartimentos não classificados, não há limite para o tamanho do bloco e pedaços de qualquer tamanho podem entrar. Esta abordagem dá ao ptmalloc uma segunda oportunidade para reutilizar o pedaço recentemente libertado.A sobrecarga de tempo para encontrar um contentor adequado é omitida,pelo que a atribuição e a libertação são mais rápidas.
  • Quando o usuário faz malloc, se os compartimentos rápidos não encontrarem pedaços adequados, o malloc primeiro procurará por pedaços livres adequados no compartimento não classificado. Se não houver um compartimento adequado, o ptmalloc colocará o pedaço do compartimento não classificado em compartimentos e, em seguida, procurará um pedaço livre adequado nos compartimentos.

caixas pequenas

  • Pedaços menores que 512 bytes são chamados de pequenos pedaços, e os compartimentos que armazenam pequenos pedaços são chamados de compartimentos pequenos. Os subscritos começam em 2 e terminam em 63, num total de 62. A diferença entre cada compartimento do compartimento pequeno é de 8 bytes, e os pedaços do mesmo compartimento pequeno têm o mesmo tamanho.
  • Cada pequeno compartimento inclui uma lista circular bidirecional de blocos livres. O pedaço livre é adicionado ao início da lista vinculada e o pedaço necessário é removido do final da lista vinculada.
  • Dois pedaços livres ligados serão fundidos num único pedaço livre. A fusão elimina o impacto da fragmentação, mas diminui a velocidade livre.
  • Ao alocar, quando o compartimento pequeno não estiver vazio, o compartimento correspondente removerá o último pedaço da lista de compartimentos e o retornará ao usuário. Ao liberar um pedaço, verifique se o pedaço antes ou depois dele está livre. Se estiver, mescle-o, ou seja, remova o pedaço da lista vinculada à qual ele pertence e mescle-o em um novo pedaço. O novo pedaço será adicionado para a frente da lista vinculada do compartimento não classificado.

caixas grandes

  • Pedaços maiores que 512 bytes são chamados de pedaços grandes, e os compartimentos salvos como pedaços grandes são chamados de compartimentos grandes e estão localizados atrás de compartimentos pequenos. Os subscritos começam em 64 e terminam em 126, num total de 63. Cada compartimento em compartimentos grandes contém um pedaço dentro de um determinado intervalo. Os pedaços são classificados por tamanho decrescente. Se o tamanho for o mesmo, eles serão classificados pelo tempo de uso mais recente.
  • Dois pedaços livres adjacentes serão mesclados em um pedaço livre.
  • Ao alocar, siga “o menor primeiro, o melhor ajuste” e percorra de cima para baixo para encontrar um pedaço cujo tamanho seja mais próximo das necessidades do usuário. Uma vez encontrado, o pedaço correspondente será dividido em dois pedaços, o pedaço do usuário (tamanho da solicitação do usuário) será retornado ao usuário e o restante do pedaço restante será adicionado à lixeira não classificada.
  • grátis é semelhante a uma lixeira pequena

caixas rápidas

Quando um programa está em execução, muitas vezes ele precisa solicitar e liberar algum espaço de memória menor. Depois que o alocador mescla vários pequenos pedaços adjacentes, pode haver uma solicitação para outro pequeno bloco de memória imediatamente, e o alocador precisa dividir um bloco da grande memória livre, o que é relativamente ineficiente, portanto, são introduzidos compartimentos rápidos.

  • Bins rápidos são buffers de alta velocidade para bins e há cerca de 10 filas de comprimento fixo (bins). Cada fast bin registra uma lista vinculada individualmente de pedaços livres (binlist, a lista vinculada individualmente é usada porque os pedaços da lista vinculada no fast bin não serão removidos), e adições e exclusões de pedaços ocorrem no front-end do lista vinculada.
  • Quando o usuário libera um pedaço que não é maior que max_fast (o valor padrão é 64 bytes), ele será colocado em compartimentos rápidos por padrão. Quando o pedaço que precisa ser alocado ao usuário é menor ou igual a max_fast, malloc irá primeiro para os compartimentos rápidos para descobrir se há um pedaço adequado. Quer os pedaços dentro de um determinado tamanho sejam alocados ou liberados, eles passarão por compartimentos rápidos.
  • Ao alocar, o primeiro pedaço recuperado na lista bin será removido e devolvido ao usuário. O pedaço livre será adicionado ao front end da lista bin indexada.

2.1.4 Inicialização

  • Na área de heap, start_brk aponta para o início do heap e brk aponta para o topo do heap. Você pode usar brk() & sbrk() para aumentar o espaço de heap alocado ao usuário. Antes de usar malloc, o valor de brk é igual a start_brk, ou seja, tamanho de heap = 0
  • No início do ptmalloc, se o espaço solicitado for menor que o limite de alocação mmap (o padrão é 128 KB), a área de alocação principal chamará sbrk() para adicionar um espaço de tamanho (128 KB + chunk_size) como heap, e o não- a área de alocação principal chamará mmap Map um espaço com tamanho HEAP_MAX_SIZE (o padrão é 1 MB para sistemas de 32 bits e 64 MB para sistemas de 64 bits) como um sub-heap
  • Quando o usuário solicita a alocação de memória, ele primeiro encontrará um pedaço adequado nesta área para o usuário.Quando o usuário liberar o pedaço no heap, o ptmalloc usará bins e bins rápidos para organizar o pedaço livre.
  • Se o tamanho do bloco que precisa ser alocado for menor que o limite de alocação mmap e o espaço de heap não for suficiente, a área de alocação principal aumentará o tamanho do heap chamando sbrk(), e a área de alocação não principal chamará mmap para mapear um novo sub-heap. Ou seja, aumente o tamanho do pedaço superior. Cada vez que o heap aumentar, o valor será alinhado a 4 KB.
  • Quando a solicitação do usuário excede o limite de alocação mmap e a área de alocação principal não consegue ser alocada usando sbrk(), ou a área de alocação não principal não pode alocar a memória necessária no bloco superior, ptmalloc tentará usar mmap() para diretamente mapear um pedaço de memória para o espaço de memória do processo. Os pedaços mapeados diretamente usando mmap() são mapeados diretamente quando liberados e não pertencem mais ao espaço de memória do processo. Qualquer acesso a esta memória irá gerar um segfault. O espaço alocado no heap ou subheap pode permanecer no espaço de memória do processo e pode ser referenciado novamente.

2.2 Alocação e liberação de memória

Processo malloc de alocação de memória

1. Obtenha o bloqueio da área de alocação para evitar conflitos multi-thread (cada processo possui um gerenciador malloc, e vários threads em um processo compartilham esse gerenciador, portanto há competição)

2. Calcule o tamanho real do pedaço de memória que precisa ser alocado

3. Se o tamanho do bloco for < max_fast (64 bytes), procure um bloco adequado em fast bins; se não existir, vá para 5

4. Se o tamanho do bloco for < 512 bytes, pesquise o pedaço nas caixas pequenas. Se existir, a alocação termina.

5. O que precisa ser alocado é uma memória grande, ou o pedaço não pode ser encontrado nas caixas pequenas:

  • a. Percorra compartimentos rápidos, mescle partes adjacentes e vincule-se a compartimentos não classificados
  • b. Percorra os pedaços na caixa não classificada:
    • ① Capaz de cortar pedaços e alocá-los diretamente, e a alocação termina
    • ② Coloque o pedaço em caixas pequenas ou grandes de acordo com o tamanho do espaço do pedaço. Depois que o percurso for concluído, vá para 6

6. O que precisa ser alocado é uma memória grande, ou nenhum pedaço adequado pode ser encontrado nas caixas pequenas e nas caixas não classificadas, e todos os pedaços nas caixas rápidas e nas caixas não classificadas foram limpos:

  • Pesquise em caixas grandes e percorra a lista vinculada até encontrar o primeiro pedaço maior que o tamanho a ser alocado e corte-o. Os pedaços restantes são colocados em caixas não classificadas e a alocação termina.

7. A recuperação de caixas rápidas e caixas não encontra um pedaço adequado. Determine se o tamanho do pedaço superior atende ao tamanho do pedaço necessário e aloque-o do pedaço superior.

8. A parte superior não consegue atender à demanda e precisa ser expandida:

  • Quando o tamanho do pedaço superior for maior que a solicitação do usuário, o pedaço superior será dividido em duas partes: pedaço do usuário e pedaço restante, onde o pedaço restante se torna o novo pedaço superior.
  • Quando o tamanho do pedaço superior é menor que a solicitação do usuário, o pedaço superior é expandido por meio da chamada de sistema sbrk() ou mmap().

9. Quando o pedaço superior não puder atender aos requisitos de alocação, se for a área de alocação principal, chame sbrk() para aumentar o tamanho do pedaço superior; se for a área de alocação não principal, chame mmap para alocar um novo subheap e aumente o tamanho do pedaço superior; ou use mmap () para atribuir diretamente:

  • Se o pedaço a ser alocado for maior ou igual ao limite de alocação mmap, use a chamada do sistema mmap para mapear um espaço chunk_size de 4 KB para o espaço de memória do programa. Em seguida, retorne o ponteiro de memória para o usuário
  • Se o pedaço a ser alocado for menor ou igual ao limite de alocação do mmap, determine se é a primeira vez que chama malloc. Se for a área de alocação principal, é necessário um trabalho de inicialização e um espaço de tamanho (chunk_size + 128 KB) alinhamento 4 KB são alocados como heap inicial. Se tiver sido inicializado,a área de alocação principal chama sbrk() para aumentar o espaço de heap.A área de alocação não principal corta um pedaço no pedaço superior para atender aos requisitos de alocação e retorna o ponteiro de memória ao usuário.

Processo livre de liberação de memória

1. Obtenha o bloqueio da área de alocação

2. Se free for um ponteiro nulo, retorne

3. Se o pedaço atual for a memória mapeada pela área de mapeamento mmap, chame munmap () para liberar a memória.

4. Se o pedaço for adjacente ao pedaço superior, mescle-o diretamente com o pedaço superior e vá para 8

5. Se o tamanho do bloco for > max_fast, coloque-o em um compartimento não classificado e verifique se há mesclagem:

  • a. Se não houver mesclagem, será gratuito.
  • b. Há uma situação de mesclagem e ela é adjacente ao pedaço superior, vá para 8

6. Se o tamanho do pedaço for <max_fast, coloque-o no fast bin e verifique se há fusão:

  • a.fast bin não altera o status do pedaço. Se não houver mesclagem, ele é gratuito.
  • b. Se houver uma situação de mesclagem, vá para 7

7. Em caixas rápidas, se os pedaços adjacentes estiverem livres, mescle os dois pedaços e coloque-os na caixa não classificada. Se o tamanho mesclado for> 64 KB, a operação de mesclagem de compartimentos rápidos será acionada. Os pedaços nos compartimentos rápidos serão percorridos e mesclados, e os pedaços mesclados serão colocados no compartimento não classificado. Se o pedaço mesclado for adjacente ao pedaço superior, ele será mesclado no pedaço superior e irá para 8

8. Se o tamanho do pedaço superior > limite de redução do mmap (o padrão é 128 KB), para a área de alocação principal, ele tentará retornar parte do pedaço superior ao sistema operacional

2.3 Precauções de uso

Para evitar a explosão da memória Glibc, você precisa prestar atenção a:

  1. A memória alocada posteriormente é liberada primeiro, porque ptmalloc reduz a memória a partir do pedaço superior. Se os pedaços adjacentes ao pedaço superior não puderem ser liberados, os pedaços abaixo do pedaço superior não poderão ser liberados.
  2. ptmalloc não é adequado para gerenciar memória de longa duração, especialmente alocação e liberação contínua e irregular de memória de longa duração, o que causará a explosão da memória ptmalloc.
  3. Programas executados por multithread em estágios não são adequados para ptmalloc. A memória desses programas é mais adequada para gerenciamento de pool de memória.
  4. Tente reduzir o número de threads no programa e evite alocações e liberações frequentes de memória. A alocação frequente levará à competição de bloqueio, levando eventualmente a um aumento nas áreas de alocação não primárias, ao aumento da fragmentação da memória e à redução do desempenho.
  5. Para evitar vazamentos de memória, ptmalloc é muito sensível a vazamentos de memória. De acordo com seu mecanismo de redução de memória, se o pedaço adjacente ao pedaço superior não for reciclado, muita memória livre sob o pedaço superior não será devolvida ao sistema operacional.
  6. Isso evita que o programa aloque muita memória ou que a memória do sistema se esgote devido ao aumento repentino da memória Glibc e o programa seja encerrado pelo sistema devido ao OOM. Estime o tamanho máximo da memória física que o programa pode usar, configure /proc/sys/vm/overcommit_memory, /proc/sys/vm/overcommit_ratio e use ulimt -v para limitar a quantidade de espaço de memória virtual que o programa pode use para evitar que o programa seja eliminado.

3. Análise comparativa dos mecanismos de implementação de ptmalloc, tcmalloc e jemalloc

ptmalloc(glibc malloc):

  • ptmalloc é o alocador de memória padrão na biblioteca GNU C (glibc) e é amplamente utilizado em sistemas Linux
  • Baseado na implementação malloc de Doug Lea, ele usa uma variedade de tecnologias, como listas vinculadas gratuitas, separadores e ligação atrasada do heap.
  • ptmalloc é caracterizado pela maturidade, estabilidade e forte integração com a biblioteca GNU C

tcmalloc(Google malloc):

  • tcmalloc é um alocador de memória desenvolvido pelo Google, usado principalmente no código C++ do Google
  • tcmalloc melhora o desempenho reduzindo a contenção de bloqueio e a fragmentação de memória
  • Use o conceito de cache local de thread (Thread-Caching Malloc) para distribuir a tarefa de alocação de memória para diferentes threads para reduzir a competição por estruturas de dados compartilhadas
  • tcmalloc também possui outras estratégias de otimização, como fusão de pequenos objetos, cache eficiente de alocador, etc.

jemalloc:

  • jemalloc é um alocador de memória de uso geral desenvolvido pela comunidade FreeBSD e gradualmente adotado por outros sistemas.
  • jemalloc se esforça para fornecer alocação de memória altamente escalável e de baixa fragmentação
  • Usa múltiplas técnicas, como regiões de memória separadas, alocadores de amigos, cache local de thread, etc.
  • jemalloc também fornece recursos avançados, como liberação de execução de thread em segundo plano, estatísticas e análises de utilização de espaço, etc.

Comparação de desempenho:

  • ptmalloc funciona bem na maioria dos casos, mas pode ter algumas condições de corrida em ambientes multithread
  • tcmalloc usa cache local de thread e reduz a competição de bloqueio, tornando-o adequado para cenários de alta simultaneidade, especialmente aplicativos de servidor multithread.
  • jemalloc é excelente em escalabilidade e fragmentação, especialmente para grandes alocações de memória e cenários de alta carga

Resumir:

  • ptmalloc é adequado para aplicações gerais e está totalmente integrado à biblioteca GNU C
  • tcmalloc é adequado para ambientes multithread de alta simultaneidade e reduz a concorrência por meio de cache local de thread.
  • jemalloc é adequado para cenários com alta escalabilidade e baixos requisitos de fragmentação, fornecendo recursos e estatísticas avançadas

Acho que você gosta

Origin blog.csdn.net/GG_Bruse/article/details/131742920
Recomendado
Clasificación