La maggior parte delle implementazioni delle funzioni di allocazione della memoria C memorizzerà le informazioni di contabilità per ciascun blocco, sia in linea che separatamente.
Un modo tipico (in linea) è di allocare effettivamente sia un'intestazione che la memoria richiesta, riempiti con una dimensione minima. Ad esempio, se hai richiesto 20 byte, il sistema potrebbe allocare un blocco di 48 byte:
- Intestazione a 16 byte contenente dimensioni, marker speciale, checksum, puntatori al blocco successivo / precedente e così via.
- Area dati di 32 byte (i 20 byte completati fino a un multiplo di 16).
L'indirizzo che ti è stato dato è l'indirizzo dell'area dati. Quindi, quando libererai il blocco, free
prenderai semplicemente l'indirizzo che gli fornisci e, supponendo che tu non abbia riempito quell'indirizzo o la memoria che lo circonda, controlla le informazioni contabili immediatamente prima di esso. Graficamente, ciò sarebbe sulla falsariga di:
____ The allocated block ____
/ \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
^
|
+-- The address you are given
Tieni presente che le dimensioni dell'intestazione e del padding sono totalmente definite dall'implementazione (in realtà, l'intera cosa è definita dall'implementazione (a) ma l'opzione di contabilità in linea è comune).
I checksum e i marcatori speciali presenti nelle informazioni contabili sono spesso la causa di errori come "Arena di memoria danneggiata" o "Doppio libero" se li sovrascrivi o li liberi due volte.
Il padding (per rendere più efficiente l'allocazione) è il motivo per cui a volte puoi scrivere un po 'oltre la fine dello spazio richiesto senza causare problemi (tuttavia, non farlo, è un comportamento indefinito e, solo perché a volte funziona, non lo fa' voglio dire che va bene farlo).
(a) Ho scritto implementazioni di malloc
in sistemi embedded in cui hai ottenuto 128 byte indipendentemente da ciò che hai richiesto (che era la dimensione della struttura più grande nel sistema), supponendo che tu abbia richiesto 128 byte o meno (richieste di più essere soddisfatto con un valore di ritorno NULL). È stata utilizzata una maschera di bit molto semplice (cioè non in linea) per decidere se un blocco di 128 byte è stato allocato o meno.
Altri che ho sviluppato avevano pool diversi per blocchi da 16 byte, blocchi da 64 byte, blocchi da 256 byte e blocchi da 1K, usando nuovamente una maschera di bit per decidere quali blocchi sono stati utilizzati o disponibili.
Entrambe queste opzioni sono riuscite a ridurre il sovraccarico delle informazioni contabili e ad aumentare la velocità malloc
e free
(non è necessario unire i blocchi adiacenti durante la liberazione), particolarmente importante nell'ambiente in cui lavoravamo.