Comment trouver combien de mémoire est réellement utilisée par un appel malloc?

Si j’appelle:

char *myChar = (char *)malloc(sizeof(char)); 

Je vais probablement utiliser plus d’un octet de mémoire, car malloc utilisera probablement lui-même de la mémoire pour garder trace des blocs libres dans le tas, et cela peut effectivement me coûter de la mémoire en alignant toujours les allocations sur certaines limites. .

Ma question est la suivante : existe-t-il un moyen de savoir combien de mémoire est réellement utilisée par un appel malloc particulier, y compris le coût effectif de l’alignement et les frais généraux utilisés par malloc / free ?

Juste pour être clair, je ne demande pas à savoir combien de mémoire un pointeur indique après un appel à malloc . Au lieu de cela, je débogue un programme qui utilise beaucoup de mémoire et je veux savoir quelles parties du code allouent combien de mémoire. J’aimerais pouvoir disposer d’une comptabilité en mémoire interne très proche des chiffres rapportés par le haut. Idéalement, j’aimerais pouvoir le faire par programmation, sur une base individuelle, au lieu d’obtenir un résumé à un sharepoint contrôle.

Il n’y a pas de solution portable à cela, mais il peut exister des solutions spécifiques au système d’exploitation pour les environnements qui vous intéressent.

Par exemple, avec glibc sous Linux, vous pouvez utiliser la fonction mallinfo() de qui renvoie une struct mallinfo . Les membres uordblks et hblkhd de cette structure contiennent l’espace adresse alloué de manière dynamic utilisé par le programme, y compris le temps système nécessaire pour la comptabilité. Si vous prenez la différence avant et après chaque appel à malloc() , vous connaîtrez la quantité d’espace utilisée par cet utilisateur. appel. (Les frais généraux ne sont pas nécessairement constants pour chaque appel de malloc() ).

En utilisant votre exemple:

 char *myChar; size_t s = sizeof(char); struct mallinfo before, after; int mused; before = mallinfo(); myChar = malloc(s); after = mallinfo(); mused = (after.uordblks - before.uordblks) + (after.hblkhd - before.hblkhd); printf("Requested size %zu, used space %d, overhead %zu\n", s, mused, mused - s); 

Vraiment cependant, les frais généraux seront probablement assez mineurs, sauf si vous effectuez un très grand nombre d’allocations très petites, ce qui est une mauvaise idée de toute façon.

Cela dépend vraiment de la mise en œuvre. Vous devriez vraiment utiliser un débogueur de mémoire. Sous Linux, l’outil Massif de Valgrind peut être utile. Il existe des bibliothèques de débogage de la mémoire comme dmalloc, …

Cela dit, frais généraux typiques:

  • 1 int pour stocker la taille + les drapeaux de ce bloc.
  • éventuellement 1 int pour stocker la taille du bloc précédent / suivant, pour aider à la formation de blocs.
  • 2 pointeurs, mais ceux-ci ne peuvent être utilisés que dans des blocs free() ‘d, étant réutilisés pour le stockage d’application dans des blocs alloués.
  • Alignement sur un type approprié, par exemple: double .
  • -1 int (oui, c’est un moins) du champ du bloc suivant / précédent contenant notre taille si nous sums un bloc alloué, car nous ne pouvons pas être bloqués tant que nous ne sums pas libérés.

Ainsi, une taille minimale peut être de 16 à 24 octets. et la surcharge minimale peut être de 4 octets.

Mais vous pouvez également satisfaire chaque allocation via des pages de mémoire de mappage (généralement 4 Ko), ce qui signifierait une surcharge pour des allocations plus petites. Je pense que OpenBSD fait cela.

Il n’y a rien de défini dans la bibliothèque C qui interroge la quantité totale de mémoire physique utilisée par un appel à malloc() . La quantité de mémoire allouée est contrôlée par le gestionnaire de mémoire connecté dans les coulisses malloc() par malloc() . Ce gestionnaire de mémoire peut allouer la quantité de mémoire supplémentaire dont il a besoin pour son suivi interne, en plus de la mémoire supplémentaire dont le système d’exploitation a besoin. Lorsque vous appelez free() , il accède au gestionnaire de mémoire, qui sait comment accéder à cette mémoire supplémentaire pour que tout soit libéré correctement, mais vous ne pouvez pas savoir combien de mémoire cela implique. Si vous avez besoin de beaucoup de détails, vous devez écrire votre propre gestionnaire de mémoire.

Si vous utilisez valgrind / Massif, il existe une option permettant d’afficher soit la valeur malloc , soit la valeur top , qui diffèrent BEAUCOUP de mon expérience. Voici un extrait du manuel Valgrind http://valgrind.org/docs/manual/ms-manual.html :

… Cependant, si vous souhaitez mesurer toute la mémoire utilisée par votre programme, vous pouvez utiliser –pages-as-heap = yes. Lorsque cette option est activée, le profilage normal de bloc de tas de Massif est remplacé par le profilage de page de niveau inférieur. Chaque page allouée via mmap et des appels système similaires est traitée comme un bloc distinct. Cela signifie que le code, les données et les segments BSS sont tous mesurés, car ils ne sont que des pages de mémoire. Même la stack est mesurée …