Question

J'ai une application longue durée de vie avec une mémoire fréquente allocation désaffectation. Est-ce que tout retour de mise en œuvre de malloc mémoire libérée au système?

Qu'est-ce que, à cet égard, le comportement de:

  • ptmalloc 1, 2 (par défaut glibc) ou 3
  • dlmalloc
  • tcmalloc (Google malloc fileté)
  • solaris 10-11 par défaut malloc et mtmalloc
  • FreeBSD 8 par défaut malloc (jemalloc)
  • Hoard malloc?

Mise à jour

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

Sans ce retour de la mémoire libérée sera troqué et à plusieurs reprises, mais cette mémoire ne contient que des déchets.

Était-ce utile?

La solution

L'analyse qui suit applique uniquement aux glibc (basé sur l'algorithme de ptmalloc2). Il y a certaines options qui semblent utiles pour retourner la mémoire libérée au système:

  1. mallopt () (défini à l'malloc.h) ne fournit une option permettant de définir la valeur de seuil de garniture avec l'une de l'option de paramètre M_TRIM_THRESHOLD, cela indique la quantité minimale de mémoire libre (en octets) a permis à la partie supérieure du segment de données. Si le montant est inférieur à ce seuil, glibc invoque brk() pour redonner la mémoire du noyau.

    La valeur par défaut de M_TRIM_THRESHOLD sous Linux est réglé sur 128K, réglage d'une valeur plus petite peut économiser de l'espace.

    Le même comportement pourrait être atteint par la mise en valeur de seuil équilibre dans l'environnement MALLOC_TRIM_THRESHOLD_ variable sans source change absolument.

    Cependant, les programmes d'essais préliminaires exécutées à l'aide M_TRIM_THRESHOLD a montré que, même si la mémoire allouée par malloc ne retourne au système, la partie restante du morceau de mémoire réelle (l'arène) initialement demandé par l'intermédiaire brk() a tendance à retenir.

  2. Il est possible de couper l'arène de la mémoire et de donner toute la 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, en laissant au moins pad octets à la fin de celui-ci et, à défaut, si moins d'une valeur de la page d'octets peut être libéré. la taille du segment est toujours un multiple d'une page, qui est 4096 octets sur i386.

    La mise en œuvre de ce comportement modifié de free() en utilisant malloc_trim pourrait être fait en utilisant la fonctionnalité de crochet de malloc. Cela ne nécessiterait aucune modification de code source à la bibliothèque glibc de base.

  3. en utilisant l'appel système madvise() dans la mise en œuvre sans glibc.

Autres conseils

La plupart des implémentations ne prennent pas la peine d'identifier les (relativement rares) cas où « blocs » entiers (quelle que soit la taille convient le système d'exploitation) ont été libérés et pourraient être renvoyés, mais il y a bien sûr des exceptions. Par exemple, et je cite la page wikipedia , dans OpenBSD:

  

Sur un appel à free, la mémoire est libérée   et unmapped de l'adresse de processus   l'espace en utilisant munmap. Ce système est   conçu pour améliorer la sécurité en prenant   avantage de la mise en page de l'espace d'adressage   Randomisation et caractéristiques page gap   mis en œuvre dans le cadre du mmap OpenBSD   appel système, et de détecter   use-after-free-insectes comme une grande mémoire   l'allocation est complètement unmapped   après qu'il est libéré, en outre utiliser des causes   une erreur de segmentation et de terminaison   du programme.

La plupart des systèmes ne sont pas aussi la sécurité axée comme OpenBSD, cependant.

Sachant cela, quand je suis un système de codage de longue durée qui a une exigence connue à être transitoire pour une grande quantité de mémoire, j'essaie toujours de fork le processus: le parent puis attend que les résultats de l'enfant [[typiquement sur une canalisation]], l'enfant fait le calcul (y compris l'allocation de mémoire), renvoie les résultats [[sur ladite canalisation]], puis se termine. De cette façon, mon processus de longue durée ne sera pas monopoliser la mémoire pendant les inutilement longues périodes entre les « pointes » occasionnels dans sa demande de mémoire. D'autres stratégies alternatives comprennent le passage à un allocateur de mémoire personnalisée pour les exigences particulières (C ++, il est relativement facile, si les langues avec des machines virtuelles en dessous telles que Java et Python en général ne le font pas).

Je traite le même problème que l'OP. Ainsi, il semble bien possible avec tcmalloc. J'ai trouvé deux solutions:

  1. compiler votre programme avec tcmalloc lié, puis lancez comme:

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    la documentation mentionne que

      

    Les taux raisonnables sont dans l'intervalle [0,10].

    mais 10 ne semble pas assez pour moi (i.e. je ne vois pas de changement).

  2. trouver 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 ce n'est pas un grand succès, il est compliqué de trouver le bon numéro, par exemple.

J'ai eu un problème similaire dans mon application, après une enquête, j'ai remarqué que, pour une raison glibc ne retourne pas la mémoire au système lorsque les objets alloués sont de petite taille (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 de retour au système. Quand j'ai changé typedef à: sortie du programme typedef x<110> X; 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é. J'ai aussi remarqué que l'utilisation malloc_trim(0) dans les deux cas la mémoire libérée au système.
Voici la 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

Pour tous mallocs « normaux », y compris ceux que vous avez mentionnés, la mémoire est libérée pour être réutilisée par votre processus, mais pas au système entier. Libérer au système tout ne se produit que lorsque vous traitez est finalement terminé.

ceux que vous la liste, ne Hoard retournera la mémoire au système ... mais si elle peut effectivement faire cela dépendra beaucoup sur le comportement de l'allocation de votre programme.

La réponse courte: Pour forcer le sous-système malloc pour revenir à la mémoire OS, utilisez malloc_trim (). Dans le cas contraire, le comportement de la mémoire de retour dépend de l'implémentation.

Le malloc(3) de FreeBSD 12 utilise jemalloc 5.1, qui renvoie la mémoire libérée ( "pages sales") à l'aide du système d'exploitation madvise(...MADV_FREE) .

mémoire libérée n'est retourné après un retard de temps commandé par opt.dirty_decay_ms et opt.muzzy_decay_ms; voir le page de manuel et ce question sur la mise en œuvre purge page sale utilisé à base de décroissance pour plus de détails.

Les versions antérieures de FreeBSD livré avec les anciennes versions de jemalloc, qui renvoie également libéré la mémoire, mais utilise un algorithme différent pour décider quoi et quand purge.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top