Pregunta

Tengo una aplicación de larga duración con frecuente asignación y desasignación de memoria.¿Alguna implementación de malloc devolverá la memoria liberada al sistema?

¿Cuál es, a este respecto, el comportamiento de:

  • ptmalloc 1, 2 (valor predeterminado de glibc) o 3
  • dlmalloc
  • tcmalloc (malloc subproceso de Google)
  • solaris 10-11 malloc y mtmalloc predeterminados
  • Malloc predeterminado de FreeBSD 8 (jemalloc)
  • ¿Acumular malloc?

Actualizar

Si tengo una aplicación cuyo consumo de memoria puede ser muy diferente durante el día y la noche (por ejemplo), ¿puedo forzar a cualquiera de los malloc a devolver la memoria liberada al sistema?

Sin dicho retorno, la memoria liberada se intercambiará y volverá a entrar muchas veces, pero dicha memoria solo contiene basura.

¿Fue útil?

Solución

El siguiente análisis se aplica sólo a glibc (basado en el algoritmo ptmalloc2). Hay algunas opciones que parecen útiles para devolver la memoria liberada de nuevo al sistema:

  1. mallopt () (definido en malloc.h) no proporciona una opción para establecer el valor umbral de ajuste usando uno de la opción de parámetro M_TRIM_THRESHOLD, esto indica la cantidad mínima de memoria libre (en bytes) permitido en la parte superior del segmento de datos. Si la cantidad es inferior a este umbral, glibc invoca brk() de devolver la memoria de kernel.

    El valor por defecto de M_TRIM_THRESHOLD en Linux se establece en 128 K, el establecimiento de un valor más pequeño podría ahorrar espacio.

    El mismo comportamiento se podría lograr mediante el establecimiento de valor umbral del ajuste en el entorno MALLOC_TRIM_THRESHOLD_ variables, sin cambios de código absolutamente.

    Sin embargo, los programas de pruebas preliminares de ejecución mediante M_TRIM_THRESHOLD ha demostrado que a pesar de que la memoria asignada por malloc no regreso al sistema, la parte restante de la porción real de memoria (la arena) solicitado inicialmente a través de brk() tiende a ser retenido.

  2. Es posible recortar el campo de la memoria y dar ninguna memoria no utilizada de nuevo al sistema llamando malloc_trim(pad) (definido en malloc.h). Esta función cambia el tamaño del segmento de datos, dejando al menos bytes pad al final de la misma y en su defecto, si menos de un valor de la página de bytes puede ser liberado. tamaño de segmento es siempre un múltiplo de una página, que es de 4.096 bytes en i386.

    La aplicación de este comportamiento modificado de free() usando malloc_trim podría hacerse utilizando la funcionalidad de gancho malloc. Esto no requeriría ningún cambio de código fuente a la biblioteca central glibc.

  3. usando la llamada al sistema madvise() dentro de la implementación libre de glibc.

Otros consejos

La mayoría de las implementaciones no se molestan en identificar esos casos (relativamente raros) en los que "bloques" completos (de cualquier tamaño que se adapte al sistema operativo) se han liberado y podrían devolverse, pero, por supuesto, hay excepciones.Por ejemplo, y cito de la página de wikipedia, en OpenBSD:

en una llamada a free, la memoria se libera y no se asigna desde el espacio de direcciones de proceso utilizando MUNMAP.Este sistema está diseñado para mejorar la seguridad aprovechando las características de aleatorización del diseño del espacio de direcciones y las características de la página GAP implementadas como parte de OpenBSD's mmapLlamada del sistema, y ​​para detectar errores de uso-después de uso, ya que una asignación de memoria grande está completamente no asignada después de liberarlo, el uso adicional provoca una falla de segmentación y la terminación del programa.

Sin embargo, la mayoría de los sistemas no están tan centrados en la seguridad como OpenBSD.

Sabiendo esto, cuando estoy codificando un sistema de larga duración que tiene un requisito transitorio de una gran cantidad de memoria, siempre trato de fork el proceso:Luego, el padre simplemente espera los resultados del hijo [[normalmente en una tubería]], el hijo hace el cálculo (incluida la asignación de memoria), devuelve los resultados [[en dicha tubería]] y luego termina.De esta manera, mi proceso de larga duración no acaparará inútilmente la memoria durante los largos periodos de tiempo entre "picos" ocasionales en su demanda de memoria.Otras estrategias alternativas incluyen cambiar a un asignador de memoria personalizado para requisitos tan especiales (C++ lo hace razonablemente fácil, aunque los lenguajes con máquinas virtuales subyacentes, como Java y Python, normalmente no lo hacen).

estoy tratando con el mismo problema que el OP. Hasta el momento, parece posible con tcmalloc. He encontrado dos soluciones:

  1. compilar el programa con tcmalloc vinculado, a continuación, poner en marcha como:

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    la documentación menciona que

      

    precios razonables están en el intervalo [0,10].

    10 pero no parece suficiente para mí (es decir, no veo ningún cambio).

  2. encuentre en algún lugar de su código en los que sería interesante para liberar toda la memoria liberada, y luego agregue este código:

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

La segunda solución ha sido muy eficaz en mi caso; La primera sería genial, pero no es muy exitosa, es complicado encontrar el número correcto, por ejemplo.

He tenido un problema similar en mi aplicación, después de algunas investigaciones me di cuenta de que por alguna razón glibc no vuelve a la memoria del sistema cuando los objetos asignados son pequeñas (en mi caso menos de 120 bytes).
Mira 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;
}

La salida del 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 no se vuelven a sistema. Cuando cambié a typedef: typedef x<110> X; salida del programa es el siguiente:

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

casi toda la memoria fue liberado. También me di cuenta que el uso de malloc_trim(0) en cualquiera de los casos la memoria liberada al sistema.
Aquí se emite después de añadir a malloc_trim el código anterior:

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 mallocs 'normales', entre ellos los que usted ha mencionado, la memoria se libera para ser reutilizado por el proceso, pero no de nuevo a todo el sistema. Liberando de nuevo a todo el sistema sólo ocurre cuando se procesa finalmente está terminado.

De los que usted lista, sólo el Tesoro volverá a la memoria del sistema ... pero si realmente puede hacer que dependerá en gran medida de comportamiento en la asignación de su programa.

La respuesta corta: Para forzar subsistema de malloc para volver a la memoria del sistema operativo, utilice malloc_trim (). De lo contrario, el comportamiento de la memoria de retorno es dependiente de la implementación.

malloc(3)

12 de FreeBSD utiliza jemalloc 5.1, que devuelve memoria liberada ( "páginas sucias") en el sistema operativo utilizando madvise(...MADV_FREE) .

memoria liberada solamente se devuelve después de un retardo de tiempo controlado por opt.dirty_decay_ms y opt.muzzy_decay_ms; ver el manual de página y este problema en la implementación basada en la descomposición sin usar sucia página purga para más detalles.

Las versiones anteriores de FreeBSD envían con versiones anteriores de jemalloc, que también devuelve la memoria liberada, pero utiliza un algoritmo diferente para decidir qué purgar y cuándo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top