web-dev-qa-db-fra.com

Les implémentations MALLOC vont-elles renvoyer la mémoire libre au système?

J'ai une application de longue date avec une allocation de mémoire fréquente. Une implémentation de MALLOC retournera-t-elle une mémoire libérée dans le système?

Ce qui est, à cet égard, le comportement de:

  • ptmalloc 1, 2 (glibc par défaut) ou 3
  • dlmalloc
  • tcmalloc (google threaded malloc)
  • solaris 10-11 par défaut MALLOC et MTMALLOCC
  • FreeBSD 8 Par défaut MALLOC (JEMALLOC)
  • HOARD MALLOC?

Mettre à jour

Si j'ai une application dont la consommation de mémoire peut être très différente pendant la journée et la nuit (par exemple), puis-je forcer l'un des Malloc à retourner à la mémoire libérée du système?

Sans cette mémoire libérée de retour sera échangée et dans plusieurs reprises, mais cette mémoire ne contient que des ordures.

56
osgx

L'analyse suivante s'applique uniquement à GLIBC (basé sur l'algorithme PTMALLOC2). Certaines options semblent utiles pour renvoyer la mémoire libérée au système:

  1. Mallopt () (défini dans malloc.h) Fournit une option permettant de définir la valeur de seuil de trim en utilisant l'une des options de paramètre M_TRIM_THRESHOLD, cela indique la quantité minimale de libre la mémoire (en octets) autorisée en haut du segment de données. Si la quantité tombe en dessous de ce seuil, Glibc invoque brk() pour redonner la mémoire au noyau.

    La valeur par défaut de M_TRIM_THRESHOLD Sous Linux est définie sur 128K, définir une valeur plus petite pourrait économiser de l'espace.

    Le même comportement pourrait être obtenu en définissant la valeur de seuil de trim dans la variable d'environnement MALLOC_TRIM_THRESHOLD_, Sans changement de source absolue.

    Cependant, des programmes de test préliminaires exécutés à l'aide de M_TRIM_THRESHOLD Ont montré que même si la mémoire allouée par MALLOC retourne au système, la partie restante de la partie réelle de la mémoire (l'arène) initialement demandée via brk() a tendance à être retenu.

  2. Il est possible de couper l'arène de mémoire et de ramener toute mémoire inutilisée au système en appelant malloc_trim(pad) (défini dans malloc.h). Cette fonction redimensionne le segment de données, laissant au moins pad octets à la fin de celui-ci et échoué si une valeur inférieure à une page d'octets peut être libérée. La taille du segment est toujours un multiple d'une page, soit 4 096 octets sur i386.

    La mise en œuvre de ce comportement modifié de free() à l'aide de malloc_trim Pourrait être effectuée à l'aide de la fonctionnalité de crochet Malloc. Cela ne nécessiterait pas de modifications de code source de la bibliothèque Core Glibc.

  3. utilisation madvise() Appel système à l'intérieur de la mise en œuvre gratuite de GLIBC.

31
Shashi

Je traite avec le même problème que l'OP. Jusqu'à présent, cela semble possible avec TCMALLOC. J'ai trouvé deux solutions:

  1. compilez votre programme avec TCMALLOCK LIEND, puis lancez-le comme suit:

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    la documentation mentionne que

    Les tarifs raisonnables sont compris entre [0,10].

    mais 10 ne semble pas assez pour moi (c'est-à-dire que je ne vois pas de changement).

  2. trouvez quelque part dans votre code où il serait intéressant de libérer toute la mémoire libérée, puis ajoutez ce code:

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

La deuxième solution a été très efficace dans mon cas; Le premier serait génial mais cela n'a pas beaucoup de succès, il est compliqué de trouver le bon numéro par exemple.

5
Laurent Debricon

J'ai eu un problème similaire dans mon application, après une enquête, j'ai remarqué que, pour une raison quelconque, Glibc ne renvoie pas la mémoire au système lorsque des objets alloués sont petits (dans mon cas moins de 120 octets).
Regardez ce code:

#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;
}

Sortie du programme:

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

environ 64 Mo ne sont pas retournés au système. Quand j'ai changé Typef à: typedef x<110> X; La sortie du programme ressemble à ceci:

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

presque toute la mémoire a été libérée. J'ai également remarqué que l'utilisation de malloc_trim(0) Dans l'une des deux cas, une mémoire libérée au système.
[.____] ici est sortie après avoir ajouté malloc_trim Au code ci-dessus:

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
5
marcinH

Pour tous les Mallocs "normaux", y compris ceux que vous avez mentionnés, la mémoire est relâchée pour être réutilisée par votre processus, mais pas revenir à l'ensemble du système. Retour à l'ensemble du système ne se produit que lorsque vous traitez finalement terminé.

4
dkantowitz

Sur ceux que vous énumérez, seuls Hoard retourneront la mémoire au système ... mais si cela peut réellement le faire dépendre beaucoup du comportement de l'allocation de votre programme.

4
Andrew McGregor

La réponse courte: forcer le sous-système MALLOC à renvoyer la mémoire au système d'exploitation, utilisez Malloc_trim (). Sinon, le comportement de la mémoire de retour est dépendant de la mise en œuvre.

3
exa

FreeBSD 12's malloc(3) UTILISATION JEMALLOC 5.1, qui retourne la mémoire libérée ("pages sales") au système d'exploitation à l'aide de madvise(...MADV_FREE).

La mémoire libérée n'est retournée qu'après un délai de temps contrôlé par opt.dirty_decay_ms et opt.muzzy_decay_ms; Voir la page manuelle et ceci problème sur la mise en oeuvre de la page de la page sale non utilisée de manière non utilisée Pour plus de détails.

Les versions antérieures de FreeBSD expédiées avec des versions plus anciennes de Jemalloc, qui renvoie également une mémoire libérée, mais utilise un algorithme différent pour décider quoi purger et quand.

1
Kevin