Pergunta

Eu tenho um aplicativo de longa vida com a memória frequente alocação-deallocation. Será que algum retorno implementação malloc libertado volta de memória para o sistema?

O que é, a este respeito, o comportamento de:

  • ptmalloc 1, 2 (padrão glibc) ou 3
  • dlmalloc
  • tcmalloc (google malloc roscado)
  • solaris malloc 10-11 padrão e mtmalloc
  • FreeBSD 8 malloc padrão (jemalloc)
  • Hoard malloc?

Atualização

Se eu tiver uma aplicação cujo consumo de memória pode ser muito diferente em diurno e noturno (por exemplo), eu posso obrigar qualquer um dos malloc de retornar memória liberada para o sistema?

Sem esse retorno memória liberada serão trocados e, em muitas vezes, mas essa memória contém apenas lixo.

Foi útil?

Solução

A análise a seguir se aplica somente a glibc (baseado no algoritmo ptmalloc2). Existem algumas opções que parecem úteis para retornar a parte de trás memória liberada para o sistema:

  1. mallopt () (definido em malloc.h) fornece uma opção para definir o valor de limiar usando uma guarnição do M_TRIM_THRESHOLD opção parâmetro, isto indica a quantidade mínima de memória livre (em bytes) permitiu na parte superior do segmento de dados. Se o valor for inferior a este limiar, glibc invoca brk() para dar a memória de volta para o kernel.

    O valor padrão de M_TRIM_THRESHOLD em Linux está definido para 128K, definindo um valor menor pode economizar espaço.

    O mesmo comportamento pode ser conseguido através da criação de valor limiar guarnição no ambiente variável MALLOC_TRIM_THRESHOLD_, com nenhuma fonte muda absolutamente.

    No entanto, os programas de testes preliminares executar usando M_TRIM_THRESHOLD mostrou que, embora a memória alocada por malloc faz retorno ao sistema, a parte restante do pedaço real de memória (arena) inicialmente solicitados via brk() tende a ser mantido.

  2. É possível cortar a arena memória e dar nenhuma volta a memória não utilizada para o sistema chamando malloc_trim(pad) (definido no malloc.h). Esta função redimensiona o segmento de dados, deixando pelo menos pad bytes no final do mesmo e não se menos de um valor de página de bytes pode ser liberado. tamanho do segmento é sempre um múltiplo de uma página, que é 4.096 bytes em i386.

    A implementação para este comportamento modificado de free() usando malloc_trim poderia ser feito usando a funcionalidade malloc gancho. Isso não exigiria qualquer alteração de código fonte para a biblioteca núcleo glibc.

  3. usando a chamada de sistema madvise() dentro do livre implementação de glibc.

Outras dicas

A maioria das implementações não se incomodam identificação dos casos (relativamente raros) onde inteiras "blocos" (de qualquer ternos tamanho do OS) foram libertados e poderiam ser devolvidos, mas há exceções curso. Por exemplo, e cito de a página da Wikipedia , no OpenBSD:

Em uma chamada para free, a memória é liberada e não mapeado a partir do endereço do processo espaço usando munmap. Este sistema é projetado para melhorar a segurança, tomando vantagem do layout do espaço de endereço características página randomização e gap implementado como parte de mmap do OpenBSD chamada de sistema, e para detectar use-after-free bugs-como uma grande memória alocação é completamente não mapeada depois de ser libertado, mais uso provoca uma falha de segmentação e terminação do programa.

A maioria dos sistemas não são tão de segurança focada como OpenBSD, no entanto.

Sabendo disso, quando eu estou codificação um sistema de longa duração que tem uma exigência conhecida-a-ser-transitória para uma grande quantidade de memória, eu sempre tento fork o processo: o pai, em seguida, apenas espera por resultados de a criança [[normalmente em uma tubulação]], a criança faz o cálculo (incluindo alocação de memória), retorna os resultados [[no dito tubo]], em seguida, finaliza. Desta forma, o meu processo de longa duração não será inutilmente monopolizando memória durante os longos tempos entre ocasionais "picos" em sua demanda por memória. Outras estratégias alternativas incluem a mudança para um alocador de memória personalizado para tais requisitos especiais (C ++ torna razoavelmente fácil, embora línguas com máquinas virtuais por baixo, como Java e Python normalmente não).

Eu estou lidando com o mesmo problema que o OP. Até agora, parece possível com tcmalloc. Eu encontrei duas soluções:

  1. compilar seu programa com tcmalloc ligada, em seguida, lançá-lo como:

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    a documentação menciona que

    taxas razoáveis ??estão no intervalo [0,10].

    mas 10 não parece suficiente para mim (isto é, não vejo nenhuma mudança).

  2. encontrar um lugar no seu código onde seria interessante para liberar toda a memória liberada, e em seguida, adicione este código:

    #include "google/malloc_extension_c.h" // C include
    #include "google/malloc_extension.h"   // C++ include
    
    /* ... */
    
    MallocExtension_ReleaseFreeMemory();
    

A segunda solução tem sido muito eficaz no meu caso; a primeira seria ótimo, mas não é muito bem sucedido, é complicado para encontrar o número certo, por exemplo.

Eu tive um problema semelhante no meu aplicativo, depois de algumas investigações notei que por algum motivo glibc não retornar memória para o sistema quando objetos alocados são pequenos (no meu caso menos de 120 bytes).
Olhe para este código:

#include <list>
#include <malloc.h>

template<size_t s> class x{char x[s];};

int main(int argc,char** argv){
    typedef x<100> X;

    std::list<X> lx;
    for(size_t i = 0; i < 500000;++i){
        lx.push_back(X());
    }

    lx.clear();
    malloc_stats();

    return 0;
}

Saída do programa:

Arena 0:
system bytes     =   64069632
in use bytes     =          0
Total (incl. mmap):
system bytes     =   64069632
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

cerca de 64 MB não são retornar ao sistema. Quando eu mudei typedef para: aparência de saída do programa typedef x<110> X; como este:

Arena 0:
system bytes     =     135168
in use bytes     =          0
Total (incl. mmap):
system bytes     =     135168
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

quase toda a memória foi libertado. Notei também que o uso de malloc_trim(0) em ambos os casos liberado memória ao sistema.
Aqui está de saída após a adição malloc_trim para o código acima:

Arena 0:
system bytes     =       4096
in use bytes     =          0
Total (incl. mmap):
system bytes     =       4096
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

Para todos os mallocs 'normais', incluindo os que você mencionou, a memória é liberada para ser reutilizada pelo seu processo, mas não volta para todo o sistema. Liberando volta para todo o sistema só acontece quando você processo está finalmente terminado.

Dos que você lista, apenas a Hoard voltará memória para o sistema ... mas se ele pode realmente fazer isso vai depender muito do comportamento de alocação do seu programa.

A resposta curta: Para forçar malloc subsistema para retornar memória para OS, use malloc_trim (). Caso contrário, o comportamento da memória retornando é dependente de implementação.

FreeBSD 12 de usos malloc(3) jemalloc 5.1, que retorna memória liberada ( "páginas sujas") para o sistema operacional usando madvise(...MADV_FREE) .

memória Freed é só voltou depois de um atraso de tempo controlado por opt.dirty_decay_ms e opt.muzzy_decay_ms; veja a página manual e este questão sobre a implementação baseada em decadência sujo não utilizado página purga para mais detalhes.

As versões anteriores do FreeBSD fornecido com versões mais antigas do jemalloc, que também retorna libertado memória, mas usa um algoritmo diferente para decidir o que purga e quando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top