446 votes

Comment free sait-il combien il doit libérer ?

En programmation C, vous pouvez passer n'importe quel type de pointeur comme argument à free, comment sait-il la taille de la mémoire allouée à libérer ? Chaque fois que je passe un pointeur à une fonction, je dois également passer la taille (par exemple, un tableau de 10 éléments doit recevoir 10 comme paramètre pour connaître la taille du tableau), mais je ne dois pas passer la taille à la fonction free. Pourquoi pas, et puis-je utiliser cette même technique dans mes propres fonctions pour éviter d'avoir à transporter la variable supplémentaire de la longueur du tableau ?

0 votes

Une question similaire : stackoverflow.com/questions/851958/ (bien que je dirais que ce n'est pas tout à fait un double)

0 votes

Le site système de jumelage Il existe un autre moyen de le faire, qui peut le déterminer sur la base du pointeur, sans surcharge dans chaque bloc.

0 votes

Ce billet l'explique bien : stackoverflow.com/questions/1957099/

400voto

Gary McGill Points 8009

Lorsque vous appelez malloc() vous spécifiez la quantité de mémoire à allouer. La quantité de mémoire réellement utilisée est légèrement supérieure à cela, et comprend des informations supplémentaires qui enregistrent (au moins) la taille du bloc. Vous ne pouvez pas accéder (de manière fiable) à ces autres informations - et vous ne devriez pas non plus :-).

Lorsque vous appelez free() il examine simplement les informations supplémentaires pour déterminer la taille du bloc.

51 votes

Pour info, par exemple, BSD a malloc_size() pour accéder de manière fiable à la taille du bloc à partir d'un malloc() ed pointeur. Mais il n'y a pas de moyen fiable et portable.

65 votes

Je pense qu'il est important de dire que ce bloc d'informations supplémentaires est situé avant le pointeur retourné.

44 votes

@gs Eh bien, cela dépend de l'implémentation. Mais, oui, c'est là où il se trouve habituellement.

172voto

paxdiablo Points 341644

La plupart des implémentations des fonctions d'allocation de mémoire en C stockeront les informations de comptabilité pour chaque bloc, soit en ligne, soit séparément.

Une méthode typique (en ligne) consiste à allouer à la fois un en-tête et la mémoire que vous avez demandée, en la complétant jusqu'à une taille minimale. Ainsi, par exemple, si vous avez demandé 20 octets, le système peut allouer un bloc de 48 octets :

  • En-tête de 16 octets contenant la taille, le marqueur spécial, la somme de contrôle, les pointeurs vers le bloc suivant/précédent et ainsi de suite.
  • Une zone de données de 32 octets (vos 20 octets arrondis à un multiple de 16).

L'adresse qui vous est alors donnée est l'adresse de la zone de données. Ensuite, lorsque vous libérez le bloc, free prendra simplement l'adresse que vous lui donnez et, en supposant que vous n'avez pas détruit cette adresse ou la mémoire qui l'entoure, vérifiera les informations comptables qui la précèdent immédiatement. Graphiquement, cela ressemblerait à ceci :

 ____ The allocated block ____
/                             \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
          ^
          |
          +-- The address you are given

Gardez à l'esprit que la taille de l'en-tête et le remplissage sont totalement définis par l'implémentation (en fait, tout est défini par l'implémentation). (a) mais l'option de comptabilité en ligne est courante).

Les sommes de contrôle et les marqueurs spéciaux qui existent dans les informations comptables sont souvent à l'origine d'erreurs telles que "Memory arena corrupted" ou "Double free" si vous les écrasez ou les libérez deux fois.

Le remplissage (pour rendre l'allocation plus efficace) est la raison pour laquelle vous pouvez parfois écrire un peu au-delà de la fin de l'espace demandé sans causer de problèmes (mais ne le faites pas, c'est un comportement non défini et ce n'est pas parce que cela fonctionne parfois qu'il faut le faire).


(a) J'ai écrit des implémentations de malloc dans les systèmes embarqués où l'on obtenait 128 octets quoi que l'on demande (c'était la taille de la plus grande structure du système), en supposant que l'on demandait 128 octets ou moins (les demandes pour plus seraient accueillies par une valeur de retour NULL). Un masque de bits très simple (c'est-à-dire, pas en ligne) était utilisé pour décider si un morceau de 128 octets était alloué ou non.

D'autres que j'ai développés avaient des pools différents pour les blocs de 16 octets, 64 octets, 256 octets et 1K, en utilisant à nouveau un masque de bits pour décider quels blocs étaient utilisés ou disponibles.

Ces deux options ont permis de réduire les frais généraux liés à l'information comptable et d'augmenter la vitesse de traitement des données. malloc et free (pas besoin de coalescer les blocs adjacents lors de la libération), particulièrement important dans l'environnement dans lequel nous travaillions.

0 votes

@paxdiablo Cela signifie-t-il que malloc n'alloue pas de blocs de mémoire contigus ?

2 votes

@user10678, la seule vraie exigence de malloc est qu'il vous donne, pour le cas réussi, un bloc de mémoire au moins aussi grand que ce que vous avez demandé. Les blocs individuels sont contigus en termes d'accès aux éléments qui les composent, mais il n'est pas nécessaire que les arènes d'où proviennent les blocs soient contiguës.

0 votes

Question connexe : Pourquoi n'y a-t-il pas de variante de malloc/free, où l'on spécifie la taille lors de la libération et où il n'est pas nécessaire de stocker la taille ?

49voto

jdehaan Points 14019

De la comp.lang.c Liste des FAQ : Comment free sait-il combien d'octets il doit libérer ?

L'implémentation de malloc/free se souvient de la taille de chaque bloc lorsqu'il est alloué, il n'est donc pas nécessaire de lui rappeler la taille lors de la libération. (Typiquement, la taille est stockée à côté du bloc alloué, c'est pourquoi les choses se cassent généralement mal si les limites du bloc alloué sont même légèrement dépassées).

5 votes

C'est une non-réponse. La question est exactement la suivante : pourquoi free peut-il vérifier de manière fiable la taille du bloc, alors que le programmeur ne dispose d'aucune fonction pour le faire ?

0 votes

Il s'agit en effet d'un détail d'implémentation de l'api malloc et il n'existe pas d'api pour récupérer cette information de manière standard (à ma connaissance). Le "système" l'enregistre et l'utilise sur free . Peut-être que la réponse ne vous satisfait pas mais je ne pense pas que vous en obtiendrez une avec des informations plus génériques :-)

6voto

Matt Joiner Points 29194

Cette réponse est tirée de Comment free() sait-il combien de mémoire il doit désallouer ? où j'ai été abrubttement empêché de répondre par une apparente question en double. Cette réponse devrait donc être pertinente pour ce double :


Pour le cas de malloc l'allocateur de tas stocke un mappage du pointeur original retourné, avec des détails pertinents nécessaires pour l'analyse de l'information. free de la mémoire plus tard. Cela implique généralement de stocker la taille de la région de mémoire sous une forme pertinente pour l'allocateur utilisé, par exemple la taille brute, ou un nœud dans un arbre binaire utilisé pour suivre les allocations, ou un compte d'"unités" de mémoire utilisées.

free n'échouera pas si vous "renommez" le pointeur, ou si vous le dupliquez de quelque manière que ce soit. Il n'est cependant pas compté dans les références, et seul le premier free sera correcte. Supplémentaire free sont des erreurs "doublement libres".

Tenter de free tout pointeur avec une valeur différente de celles retournées par les précédents malloc et qui n'est pas encore libre est une erreur. Il n'est pas possible de libérer partiellement les régions de mémoire renvoyées par la commande malloc .

0 votes

J'ai modifié la valeur d'un pointeur renvoyé par un appel malloc. Et je l'ai libéré sans erreur. Pourquoi ? Voir ici : stackoverflow.com/questions/42618390/

3voto

LiraNuna Points 21565

malloc() et free() dépendent du système et du compilateur, il est donc difficile de donner une réponse précise.

Plus d'informations sur cette autre question .

2 votes

Ils sont vraiment dépendants de la bibliothèque (typiquement la bibliothèque C, qui est généralement très étroitement liée au système d'exploitation). Pour le compilateur, ce ne sont que des fonctions.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X