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:
- En-tête de 16 octets contenant la taille, un marqueur spécial, une somme de contrôle, des pointeurs vers le bloc suivant / précédent, etc.
- Zone de données de 32 octets (vos 20 octets remplis à 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
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:
____ 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, 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
et free
(pas besoin de fusionner des blocs adjacents lors de la libération), particulièrement important dans l'environnement que nous travaillions dans.