En programmation C, vous pouvez passer n'importe quel type de pointeur que vous aimez comme argument à libérer, comment connaît-il la taille de la mémoire allouée à libérer? Chaque fois que je passe un pointeur vers une fonction, je dois également passer la taille (c'est-à-dire qu'un tableau de 10 éléments doit recevoir 10 comme paramètre pour connaître la taille du tableau), mais je n'ai pas à transmettre la taille à la fonction libre. Pourquoi pas, et puis-je utiliser cette même technique dans mes propres fonctions pour m'éviter d'avoir à contourner la variable supplémentaire de la longueur du tableau?
385
Réponses:
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 (de manière fiable) accéder à ces autres informations - et vous ne devriez pas non plus :-).Lorsque vous appelez
free()
, il regarde simplement les informations supplémentaires pour savoir quelle est la taille du bloc.la source
malloc_size()
accéder de manière fiable à la taille de bloc à partir d'unmalloc()
pointeur ed. Mais il n'y a aucun moyen fiable et portable.free()
le programmeur devait indiquer avec précision la taille dumalloc()
bloc? Les fuites de mémoire sont déjà assez mauvaises.malloc()
etfree()
, mais vous devez stocker la taille d'un tableau? Pourquoi ne permettraient-ils pas de faire quelque chose commeblockSize(ptr)
s'ils stockaient quand même les informations?La plupart des implémentations des fonctions d'allocation de mémoire C stockent des informations comptables pour chaque bloc, soit en ligne, soit séparément.
Une façon typique (en ligne) consiste à allouer à la fois un en-tête et la mémoire que vous avez demandée, remplie à une taille minimale. Ainsi, par exemple, si vous avez demandé 20 octets, le système peut allouer un bloc de 48 octets:
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
prenez simplement l'adresse que vous lui donnez et, en supposant que vous n'avez pas bourré cette adresse ou la mémoire qui l'entoure, vérifiez les informations comptables immédiatement avant. Graphiquement, ce serait dans le sens de:Gardez à l'esprit que la taille de l'en-tête et le remplissage sont totalement définis par l'implémentation (en fait, le 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 «Arène mémoire corrompue» ou «Double libre» 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 votre espace demandé sans causer de problèmes (encore, ne faites pas cela, c'est un comportement indéfini et, juste parce que cela fonctionne parfois, ne fonctionne pas) Je veux dire que c'est correct de le faire).
(a) J'ai écrit des implémentations de
malloc
dans les systèmes embarqués où vous avez obtenu 128 octets, peu importe ce que vous avez demandé (c'était la taille de la plus grande structure du système), en supposant que vous avez demandé 128 octets ou moins (les demandes de plus seraient être rencontré avec une valeur de retour NULL). Un masque de bits très simple (c'est-à-dire non en ligne) a été utilisé pour décider si un bloc de 128 octets était alloué ou non.D'autres que j'ai développés avaient différents pools pour les blocs de 16 octets, les blocs de 64 octets, les blocs de 256 octets et les blocs de 1 Ko, utilisant à nouveau un masque de bits pour décider quels blocs étaient utilisés ou disponibles.
Ces deux options ont réussi à réduire les frais généraux de l'information comptable et d'augmenter la vitesse
malloc
etfree
(pas besoin de fusionner des blocs adjacents lors de la libération), particulièrement important dans l'environnement que nous travaillions dans.la source
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 de la façon dont vous accédez aux éléments qu'ils contiennent, mais il n'est pas nécessaire que les arènes d'où proviennent les blocs soient contiguës.void *x = malloc(200); free(x, 500);
on ne va pas bien finir :-) Dans tous les cas, l' efficacité, la réelle taille de la mémoire tampon peut être plus grande (vous ne pouvez pas compter sur ce sujet ).De la
comp.lang.c
liste FAQ: comment free sait-il combien d'octets libérer?L'implémentation malloc / free se souvient de la taille de chaque bloc lorsqu'elle est allouée, il n'est donc pas nécessaire de lui rappeler la taille lors de la libération. (En règle générale, 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)
la source
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 applicables :-)Cette réponse est déplacée à partir de Comment free () sait-il combien de mémoire désallouer? où j'ai été brutalement empêché de répondre par une question apparemment en double. Cette réponse devrait alors être pertinente pour ce double:
Dans le cas de
malloc
, l'allocateur de tas stocke un mappage du pointeur renvoyé d'origine, avec les détails pertinents nécessaires pourfree
ing la mémoire plus tard. Cela implique généralement le stockage de la taille de la région de mémoire sous quelque forme que ce soit 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 décompte des "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. Elle n'est cependant pas comptée en référence, et seule la premièrefree
sera correcte. Lesfree
s supplémentaires sont des erreurs "double free".Tentative de
free
n'importe quel pointeur avec une valeur différente de celles renvoyées par lesmalloc
s précédents et non libérée est une erreur. Il n'est pas possible de libérer partiellement les régions de mémoire renvoyées parmalloc
.la source
Sur une note connexe, la bibliothèque GLib a des fonctions d'allocation de mémoire qui n'enregistrent pas la taille implicite - et vous passez simplement le paramètre de taille à free. Cela peut éliminer une partie des frais généraux.
la source
malloc()
etfree()
dépendent du système / compilateur, il est donc difficile de donner une réponse spécifique.Plus d'informations sur cette autre question .
la source
Le gestionnaire de tas a stocké la quantité de mémoire appartenant au bloc alloué quelque part lorsque vous avez appelé
malloc
.Je n'en ai jamais implémenté un moi-même, mais je suppose que la mémoire juste en face du bloc alloué peut contenir les métadonnées.
la source
La technique originale était d'allouer un bloc légèrement plus grand et de stocker la taille au début, puis de donner à l'application le reste du blog. L'espace supplémentaire contient une taille et peut-être des liens pour enfiler les blocs libres pour une réutilisation.
Cependant, il existe certains problèmes avec ces astuces, comme un mauvais comportement de gestion du cache et de la mémoire. Utiliser la mémoire directement dans le bloc tend à paginer inutilement les choses et crée également des pages sales qui compliquent le partage et la copie sur écriture.
Une technique plus avancée consiste donc à conserver un répertoire séparé. Des approches exotiques ont également été développées où les zones de mémoire utilisent les mêmes tailles de puissance de deux.
En général, la réponse est: une structure de données distincte est allouée pour conserver l'état.
la source
Pour répondre à la deuxième moitié de votre question: oui, vous le pouvez, et un schéma assez courant en C est le suivant:
la source
Lorsque nous appelons malloc, cela consomme simplement plus d'octets par rapport à son exigence. Cette consommation de plus d'octets contient des informations telles que la somme de contrôle, la taille et d'autres informations supplémentaires. Lorsque nous appelons gratuitement à ce moment-là, il va directement à cette information supplémentaire où il trouve l'adresse et trouve également combien de bloc sera libre.
la source
pour répondre à la deuxième question, oui, vous pouvez (en quelque sorte) utiliser la même technique qu'en
malloc()
affectant simplement la première cellule de chaque tableau à la taille du tableau. qui vous permet d'envoyer le tableau sans envoyer d'argument de taille supplémentaire.la source