In der C-Programmierung können Sie jede Art von Zeiger als Argument an free übergeben. Woher weiß er, wie groß der Speicher ist, der freigegeben werden soll? Immer wenn ich einen Zeiger an eine Funktion übergebe, muss ich auch die Größe übergeben (d.h. ein Array mit 10 Elementen muss 10 als Parameter erhalten, um die Größe des Arrays zu kennen), aber ich muss die Größe nicht an die free-Funktion übergeben. Warum nicht, und kann ich dieselbe Technik in meinen eigenen Funktionen verwenden, damit ich nicht die zusätzliche Variable für die Länge des Arrays mit mir herumschleppen muss?
Antworten
Zu viele Anzeigen?Wenn Sie anrufen malloc()
geben Sie die Menge des zuzuweisenden Speichers an. Die tatsächlich verwendete Speichermenge ist etwas größer als diese und enthält zusätzliche Informationen, die (zumindest) die Größe des Blocks aufzeichnen. Auf diese anderen Informationen können Sie nicht (zuverlässig) zugreifen - und das sollten Sie auch nicht :-).
Wenn Sie anrufen free()
Wenn Sie das Programm nicht verwenden, wird einfach anhand der zusätzlichen Informationen ermittelt, wie groß der Block ist.
Die meisten Implementierungen von C-Speicherzuweisungsfunktionen speichern Buchhaltungsinformationen für jeden Block, entweder in-line oder separat.
Eine typische Methode (in-line) besteht darin, sowohl einen Header als auch den angeforderten Speicher zuzuweisen, der auf eine bestimmte Mindestgröße aufgefüllt wird. Wenn Sie also beispielsweise 20 Byte angefordert haben, kann das System einen 48-Byte-Block zuweisen:
- 16-Byte-Header mit Größe, spezieller Markierung, Prüfsumme, Verweis auf den nächsten/vorherigen Block usw.
- 32 Bytes Datenbereich (Ihre 20 Bytes werden auf ein Vielfaches von 16 aufgefüllt).
Die Adresse, die Sie dann erhalten, ist die Adresse des Datenbereichs. Wenn Sie dann den Block freigeben, free
nimmt einfach die Adresse, die Sie ihm geben, und prüft - vorausgesetzt, Sie haben diese Adresse oder den Speicher um sie herum nicht vollgestopft - die Buchhaltungsinformationen unmittelbar davor. Grafisch würde das in etwa so aussehen:
____ The allocated block ____
/ \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
^
|
+-- The address you are given
Denken Sie daran, dass die Größe des Headers und des Paddings vollständig durch die Implementierung definiert sind (eigentlich ist das ganze Ding durch die Implementierung definiert (a) aber die Option der Inline-Abrechnung ist eine gängige Option).
Die Prüfsummen und speziellen Markierungen, die in den Buchhaltungsinformationen vorhanden sind, sind oft die Ursache für Fehler wie "Memory arena corrupted" oder "Double free", wenn Sie sie überschreiben oder zweimal freigeben.
Das Auffüllen (um die Zuteilung effizienter zu machen) ist der Grund, warum man manchmal etwas über das Ende des angeforderten Platzes hinaus schreiben kann, ohne Probleme zu verursachen (trotzdem sollte man das nicht tun, es ist ein undefiniertes Verhalten, und nur weil es manchmal funktioniert, bedeutet das nicht, dass es in Ordnung ist, es zu tun).
(a) Ich habe Implementierungen geschrieben von malloc
in eingebetteten Systemen, wo man 128 Bytes erhielt, egal was man verlangte (das war die Größe der größten Struktur im System), vorausgesetzt, man verlangte 128 Bytes oder weniger (Anfragen nach mehr würden mit einem NULL-Rückgabewert beantwortet). Eine sehr einfache Bit-Maske (d.h. nicht in-line) wurde verwendet, um zu entscheiden, ob ein 128-Byte-Block zugewiesen wurde oder nicht.
Andere, die ich entwickelt habe, hatten verschiedene Pools für 16-Byte-Blöcke, 64-Byte-Blöcke, 256-Byte-Blöcke und 1K-Blöcke, wobei wiederum eine Bitmaske verwendet wurde, um zu entscheiden, welche Blöcke verwendet wurden oder verfügbar waren.
Mit diesen beiden Optionen konnte der Aufwand für die Buchhaltungsinformationen verringert und die Geschwindigkeit der malloc
y free
(keine Notwendigkeit, benachbarte Blöcke beim Freigeben zusammenzulegen), was in der Umgebung, in der wir gearbeitet haben, besonders wichtig war.
より comp.lang.c
FAQ-Liste: Woher weiß free, wie viele Bytes es freigeben muss?
Die malloc/free-Implementierung merkt sich die Größe eines jeden Blocks, wenn er alloziert wird, so dass es nicht notwendig ist, ihn beim Freigeben an die Größe zu erinnern. (Normalerweise wird die Größe neben dem zugewiesenen Block gespeichert, weshalb es normalerweise zu Problemen kommt, wenn die Grenzen des zugewiesenen Blocks auch nur leicht überschritten werden)
Diese Antwort wird verlegt von Woher weiß free(), wie viel Speicher es freigeben muss? wo ich durch eine scheinbar doppelte Frage abrupt an der Beantwortung gehindert wurde. Diese Antwort sollte dann für dieses Duplikat relevant sein:
Für den Fall, dass malloc
speichert der Heap Allocator eine Zuordnung des ursprünglich zurückgegebenen Zeigers zu den relevanten Details, die für free
den Speicher später zu löschen. Dazu gehört in der Regel die Speicherung der Größe des Speicherbereichs in einer für den verwendeten Allokator relevanten Form, z. B. als Rohgröße, als Knoten in einem Binärbaum zur Verfolgung von Zuweisungen oder als Anzahl der verwendeten Speicher-"Einheiten".
free
schlägt nicht fehl, wenn Sie den Zeiger "umbenennen" oder ihn in irgendeiner Weise duplizieren. Er wird jedoch nicht als Referenz gezählt, und nur der erste free
richtig sein wird. Zusätzlich free
s sind "doppelt freie" Fehler.
Der Versuch, die free
jeder Zeiger mit einem anderen Wert als dem, der von früheren malloc
s, und noch nicht befreit ist ein Fehler. Es ist nicht möglich, Speicherbereiche teilweise freizugeben, die von malloc
.
- See previous answers
- Weitere Antworten anzeigen