Question

S'il vous plaît aider :) OS: Linux

Où dans "Sleep (1000);", à ce moment "en haut (affichage des tâches Linux)" m'a écrit 7,7% d'utilisation de MEM. Valgrind: non trouvé la fuite de mémoire.

Je comprends, a écrit correctement et tout le résultat malloc est nul. Mais pourquoi en ce temps «sommeil», mon programme n'a pas diminué la mémoire? Qu'est-ce qui manque?

Désolé pour mon mauvais anglais, merci


~ # tmp_soft
For : Is it free??  no
Is it free??  yes
For 0 
For : Is it free??  no
Is it free??  yes
For 1 
END : Is it free??  yes
END 

~ #top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                
23060 root      20   0  155m 153m  448 S    0  7.7   0:01.07 tmp_soft    

Source complète: tmp_soft.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct cache_db_s
{
 int       table_update;
 struct    cache_db_s * p_next;
};

void free_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t;
 while (*cache_db != NULL)
 {
  cache_db_t = *cache_db;
  *cache_db = (*cache_db)->p_next;
  free(cache_db_t);
  cache_db_t = NULL;
 }
 printf("Is it free??  %s\n",*cache_db==NULL?"yes":"no");
}

void make_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t = NULL;
 int n = 10000000;

 for (int i=0; i = n; i++)
 {
  if ((cache_db_t=malloc(sizeof(struct cache_db_s)))==NULL) {
   printf("Error : malloc 1 -> cache_db_s (no free memory) \n");
   break;
  }
  memset(cache_db_t, 0, sizeof(struct cache_db_s));

  cache_db_t->table_update = 1; // tmp 

  cache_db_t->p_next = *cache_db;
  *cache_db = cache_db_t;
  cache_db_t = NULL;
 }
}

int main(int argc, char **argv)
{
 struct cache_db_s * cache_db = NULL;

 for (int ii=0; ii  2; ii++) {
  make_cache_db(&cache_db);
  printf("For : Is it free??  %s\n",cache_db==NULL?"yes":"no");
  free_cache_db(&cache_db);
  printf("For %d \n", ii);
 }

 printf("END : Is it free??  %s\n",cache_db==NULL?"yes":"no");
 printf("END \n");
 sleep(1000);
 return 0;
}
Était-ce utile?

La solution

Si vous essayez de déterminer si votre programme a une fuite de mémoire, alors top N'est-ce pas le bon outil pour le travail (valrind est).

top Affiche l'utilisation de la mémoire vu par le système d'exploitation. Même si tu appelles free, Rien ne garantit que la mémoire libérée serait retournée au système d'exploitation. En règle générale, ce n'est pas le cas. Néanmoins, la mémoire devient «libre» dans le sens où votre processus peut l'utiliser pour des allocations ultérieures.

Éditer Si ton libc le soutient, vous pouvez essayer d'expérimenter M_TRIM_THRESHOLD. Même si vous suivez ce chemin, cela va être délicat (un seul bloc utilisé assis près du haut du tas empêcherait toute la mémoire libre en dessous d'être libérée au système d'exploitation).

Autres conseils

Pour de bonnes raisons, pratiquement aucun allocateur de mémoire ne renvoie des blocs au système d'exploitation


La mémoire ne peut être supprimée que de votre programme en unités de pages, et même cela est peu susceptible d'être observé.

Calloc (3) et Malloc (3) interagissent avec le noyau pour obtenir de la mémoire, si nécessaire. Mais très, très peu d'implémentations de gratuits (3) renvoient jamais de la mémoire au noyau1, ils l'ajoutent simplement à une liste gratuite que Calloc () et Malloc () consulteront plus tard afin de réutiliser les blocs libérés. Il y a de bonnes raisons pour cette approche de conception.

Même si un libre () voulait retourner de la mémoire au système, il aurait besoin d'au moins une page de mémoire contigu afin d'amener le noyau pour protéger la région, donc la libération d'un petit bloc entraînerait un changement de protection que s'il était la dernière petit bloc dans une page.

Théorie du fonctionnement

Ainsi, Malloc (3) obtient de la mémoire du noyau lorsqu'il en a besoin, finalement dans des unités de multiples de pages discrètes. Ces pages sont divisées ou consolidées comme le programme l'exige. Malloc et coopérer librement pour maintenir un répertoire. Ils fusionnent des blocs libres adjacents lorsque cela est possible afin de pouvoir fournir de gros blocs. Le répertoire peut ou non impliquer l'utilisation de la mémoire dans des blocs libérés pour former une liste liée. (L'alternative est un peu plus partagée par la mémoire et les paginations, et il implique d'allocation spécifiquement de la mémoire pour le répertoire.) Malloc et libre ont peu ou pas de possibilité d'appliquer l'accès à des blocs individuels même lorsque le code de débogage spécial et facultatif est compilé dans le programme.


1. Le fait que très peu d'implémentations de libre () tentent de retourner la mémoire au système n'est pas du tout due aux implémentateurs qui se relâchent.

L'interaction avec le noyau est beaucoup plus lent que d'exécuter le code de bibliothèque, et l'avantage serait faible. La plupart des programmes ont une empreinte de mémoire en régime permanent ou croissant, de sorte que le temps passé à analyser le tas à la recherche d'une mémoire retournable serait complètement gaspillé. D'autres raisons incluent le fait que la fragmentation interne rend les blocs alignés par la page qui existent peu, et il est probable que le retour d'un bloc fragmenterait les blocs de chaque côté. Enfin, les quelques programmes qui renvoient de grandes quantités de mémoire sont susceptibles de contourner Malloc () et de simplement allouer et gratuitement des pages de toute façon.

Généralement gratuit () ne redonne pas de la mémoire physique au système d'exploitation, ils sont toujours mappés dans la mémoire virtuelle de votre processus. Si vous allouez un gros morceau de mémoire, LIBC peut le répartir par mmap (); Ensuite, si vous le libérez, LiBC peut libérer la mémoire à OS par Munmap (), dans ce cas, le top montrera que votre utilisation de la mémoire baisse.

Donc, si vous ne souhaitez pas libérer de la mémoire pour OS explicitement, vous pouvez utiliser mmap () / munmap ().

Lorsque vous free() Mémoire, il est renvoyé dans le pool de mémoire de la bibliothèque C et non retourné au système d'exploitation. Dans la vision du système d'exploitation, comme vous le voyez à travers top, le processus est toujours "en utilisant" cette mémoire. Dans le processus, la bibliothèque C a pris en compte la mémoire et pourrait renvoyer le même pointeur à partir de malloc() à l'avenir.

Je vais l'expliquer davantage avec un début différent:

Pendant vos appels à malloc, l'implémentation de la bibliothèque standard peut déterminer que le processus n'a pas suffisamment de mémoire allouée à partir du système d'exploitation. À ce moment-là, la bibliothèque passera un appel système pour recevoir plus de mémoire du système d'exploitation au processus (par exemple, sbrk() ou VirtualAlloc() Le système appelle respectivement UNIX ou Windows).

Une fois que la bibliothèque demande une mémoire supplémentaire du système d'exploitation, il ajoute cette mémoire à sa structure de mémoire disponible pour revenir à partir de malloc. Appels ultérieurs à malloc utilisera cette mémoire jusqu'à ce qu'elle s'épuise. Ensuite, la bibliothèque demande au système d'exploitation encore plus de mémoire.

Lorsque vous free Mémoire, la bibliothèque ne renvoie généralement pas la mémoire au système d'exploitation. Il y a plusieurs raisons à cela. L'une des raisons est que l'auteur de la bibliothèque pensait que vous appellerez malloc encore. Si vous n'appelez pas malloc Encore une fois, votre programme se terminera probablement bientôt. Dans les deux cas, il n'y a pas beaucoup d'avantages pour retourner la mémoire au système d'exploitation.

Une autre raison pour laquelle la bibliothèque peut ne pas renvoyer la mémoire au système d'exploitation est que la mémoire du système d'exploitation est allouée dans de grandes gammes contiguës. Il ne peut être renvoyé que lorsqu'une gamme contiguë entière n'est plus utilisée. Le modèle d'appel malloc et free peut ne pas effacer toute la gamme d'utilisation.

Deux problèmes:

  • Dans make_cache_db(), la ligne

    for (int i=0; i = n; i++)
    

    devrait probablement lire

    for (int i=0; i<n; i++)
    

    Sinon, vous n'éloquerez qu'un seul cache_db_s nœud.

  • La façon dont vous affectez cache_db dans make_cache_db() semble être buggy. Il semble que votre intention soit de renvoyer un pointeur vers le premier élément de la liste liée; Mais parce que tu réassigne cache_db Dans chaque itération de la boucle, vous finirez par retourner un pointeur vers le dernière élément de la liste.

    Si vous libérez plus tard la liste en utilisant free_cache_db(), cela vous fera fuir la mémoire. Pour le moment, cependant, ce problème est masqué par le bogue décrit dans le point précédent, ce qui vous fait allouer des listes de seule longueur 1.

Indépendamment de ces bogues, le point soulevé par AIX est très valable: la bibliothèque d'exécution n'a pas besoin de renvoyer tout free()D Mémoire au système d'exploitation.

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