In der C-Programmierung können Sie jede Art von Zeiger, die Sie möchten, als Argument an free übergeben. Woher weiß es, wie groß der zugewiesene Speicher ist, der freigegeben werden soll? Immer wenn ich einen Zeiger auf eine Funktion übergebe, muss ich auch die Größe übergeben (dh ein Array von 10 Elementen muss 10 als Parameter erhalten, um die Größe des Arrays zu kennen), aber ich muss die Größe nicht an die übergeben freie Funktion. Warum nicht, und kann ich dieselbe Technik in meinen eigenen Funktionen verwenden, um zu vermeiden, dass ich die zusätzliche Variable der Array-Länge umfahren muss?
385
Antworten:
Wenn Sie anrufen
malloc()
, geben Sie die zuzuweisende Speichermenge an. Die tatsächlich verwendete Speichermenge ist geringfügig höher und enthält zusätzliche Informationen, die (zumindest) aufzeichnen, wie groß der Block ist. Sie können nicht (zuverlässig) auf diese anderen Informationen zugreifen - und sollten Sie auch nicht :-).Wenn Sie anrufen
free()
, werden einfach die zusätzlichen Informationen angezeigt, um herauszufinden, wie groß der Block ist.quelle
malloc_size()
zuverlässig über einenmalloc()
ed-Zeiger auf die Blockgröße zugreifen . Aber es gibt keinen zuverlässigen, tragbaren Weg.free()
der Programmierer genau angeben muss, wie groß dermalloc()
Block war? Die Speicherlecks sind so schlimm wie sie sind.malloc()
und verfügbarfree()
, aber Sie müssen die Größe eines Arrays speichern? Warum würden sie es nicht möglich machen, so etwas zu tun,blockSize(ptr)
wenn sie die Informationen trotzdem speichern?Die meisten Implementierungen von C-Speicherzuweisungsfunktionen speichern Abrechnungsinformationen für jeden Block entweder inline oder separat.
Ein typischer Weg (inline) besteht darin, sowohl einen Header als auch den von Ihnen angeforderten Speicher zuzuweisen, der auf eine Mindestgröße aufgefüllt ist. Wenn Sie beispielsweise nach 20 Bytes gefragt haben, weist das System möglicherweise einen 48-Byte-Block zu:
Die Ihnen dann gegebene Adresse ist die Adresse des Datenbereichs. Wenn Sie den Block
free
freigeben, nehmen Sie einfach die Adresse, die Sie ihm gegeben haben, und überprüfen Sie die Buchhaltungsinformationen unmittelbar davor, vorausgesetzt, Sie haben diese Adresse oder den Speicher um ihn herum nicht vollgestopft. Grafisch wäre das wie folgt:Beachten Sie, dass die Größe des Headers und des Auffüllens vollständig implementierungsdefiniert sind (tatsächlich ist das Ganze implementierungsdefiniert (a) aber die Inline-Abrechnungsoption ist eine übliche).
Die Prüfsummen und speziellen Markierungen in den Buchhaltungsinformationen sind häufig die Ursache für Fehler wie "Speicherbereich beschädigt" oder "Doppelt frei", wenn Sie sie überschreiben oder zweimal freigeben.
Das Auffüllen (um die Zuordnung effizienter zu gestalten) ist der Grund, warum Sie manchmal ein wenig über das Ende Ihres angeforderten Speicherplatzes hinaus schreiben können, ohne Probleme zu verursachen (tun Sie das trotzdem nicht, es ist undefiniertes Verhalten und, nur weil es manchmal funktioniert, nicht) Ich meine, es ist okay, es zu tun.
(a) Ich habe Implementierungen von geschrieben
malloc
in eingebetteten Systemen bei denen Sie 128 Bytes erhalten haben, unabhängig davon, wonach Sie gefragt haben (das war die Größe der größten Struktur im System), vorausgesetzt, Sie haben nach 128 Bytes oder weniger gefragt (Anfragen nach mehr würden mit einem NULL-Rückgabewert erfüllt sein). Eine sehr einfache Bitmaske (dh nicht inline) wurde verwendet, um zu entscheiden, ob ein 128-Byte-Block zugewiesen wurde oder nicht.Andere, die ich entwickelt habe, hatten unterschiedliche Pools für 16-Byte-Chunks, 64-Byte-Chunks, 256-Byte-Chunks und 1K-Chunks, wobei wiederum eine Bitmaske verwendet wurde, um zu entscheiden, welche Blöcke verwendet wurden oder verfügbar waren.
Beiden Optionen verwalten den Aufwand der Accounting - Informationen zu reduzieren und die Geschwindigkeit zu erhöhen
malloc
undfree
(keine Notwendigkeit zu benachbarten Blöcke zusammenwachsen , wenn Befreiung), besonders wichtig in der Umgebung , die wir in arbeiten.quelle
malloc
ist, dass Sie für den erfolgreichen Fall einen Speicherblock erhalten, der mindestens so groß ist, wie Sie es gewünscht haben. Einzelne Blöcke sind in Bezug auf den Zugriff auf Elemente in ihnen zusammenhängend, es ist jedoch nicht erforderlich, dass die Arenen, aus denen die Blöcke stammen, zusammenhängend sind.void *x = malloc(200); free(x, 500);
wird nicht gut enden :-) Aus Effizienzgründen kann die tatsächliche Größe des Puffers in jedem Fall größer sein (darauf können Sie sich einfach nicht verlassen).Aus der
comp.lang.c
FAQ-Liste: Woher weiß free, wie viele Bytes frei sind?Die malloc / free-Implementierung speichert die Größe jedes zugewiesenen Blocks, sodass es beim Freigeben nicht erforderlich ist, ihn an die Größe zu erinnern. (Normalerweise wird die Größe neben dem zugewiesenen Block gespeichert, weshalb die Dinge normalerweise schlecht brechen, wenn die Grenzen des zugewiesenen Blocks sogar leicht überschritten werden.)
quelle
free
. Vielleicht befriedigt Sie die Antwort nicht, aber ich glaube nicht, dass Sie eine mit allgemeiner anwendbaren Informationen erhalten :-)Diese Antwort wird verschoben von Woher weiß free (), wie viel Speicher freigegeben werden muss? wo ich durch eine scheinbar doppelte Frage daran gehindert wurde, zu antworten. Diese Antwort sollte dann für dieses Duplikat relevant sein:
Für den Fall von
malloc
speichert der Heap-Allokator eine Zuordnung des ursprünglich zurückgegebenen Zeigers zu relevanten Details,free
die später für den Speicher benötigt werden . Dies beinhaltet typischerweise das Speichern der Größe des Speicherbereichs in der für den verwendeten Allokator relevanten Form, beispielsweise der Rohgröße, oder eines Knotens in einem Binärbaum, der zum Verfolgen von Zuordnungen verwendet wird, oder einer Anzahl von verwendeten Speichereinheiten.free
schlägt nicht fehl, wenn Sie den Zeiger "umbenennen" oder in irgendeiner Weise duplizieren. Es wird jedoch keine Referenz gezählt, und nur die erstefree
ist korrekt. Zusätzlichefree
s sind "doppelt freie" Fehler.Der Versuch,
free
einen Zeiger mit einem anderen Wert als dem vonmalloc
s zuvor zurückgegebenen und noch nicht freigegebenen Wert zu verwenden , ist ein Fehler. Es ist nicht möglich, Speicherbereiche, von denen zurückgegeben wird, teilweise freizugebenmalloc
.quelle
In einem ähnlichen Zusammenhang verfügt die GLib- Bibliothek über Speicherzuweisungsfunktionen, die keine implizite Größe speichern - und dann übergeben Sie einfach den Parameter size an free. Dies kann einen Teil des Overheads eliminieren.
quelle
malloc()
undfree()
sind system- / compilerabhängig, so dass es schwierig ist, eine bestimmte Antwort zu geben.Weitere Informationen zu dieser anderen Frage .
quelle
Der Heap-Manager hat die Speichermenge, die zu dem zugewiesenen Block gehört, irgendwo gespeichert, als Sie aufgerufen haben
malloc
.Ich habe selbst nie einen implementiert, aber ich denke, der Speicher direkt vor dem zugewiesenen Block enthält möglicherweise die Metainformationen.
quelle
Die ursprüngliche Technik bestand darin, einen etwas größeren Block zuzuweisen und die Größe am Anfang zu speichern, um dann der Anwendung den Rest des Blogs zu geben. Der zusätzliche Platz hat eine Größe und möglicherweise Links, um die freien Blöcke zur Wiederverwendung zusammenzufädeln.
Es gibt jedoch bestimmte Probleme mit diesen Tricks, wie z. B. schlechtes Cache- und Speicherverwaltungsverhalten. Die Verwendung von Speicher direkt im Block führt dazu, dass Dinge unnötig eingeblendet werden, und es entstehen auch schmutzige Seiten, die das Teilen und das Kopieren beim Schreiben erschweren.
Eine fortgeschrittenere Technik besteht also darin, ein separates Verzeichnis zu führen. Es wurden auch exotische Ansätze entwickelt, bei denen Speicherbereiche dieselbe Zweierpotenzgröße verwenden.
Im Allgemeinen lautet die Antwort: Eine separate Datenstruktur wird zugewiesen, um den Status beizubehalten.
quelle
Um die zweite Hälfte Ihrer Frage zu beantworten: Ja, das können Sie, und ein ziemlich häufiges Muster in C ist das Folgende:
quelle
Wenn wir malloc aufrufen, verbraucht es einfach mehr Byte von seiner Anforderung. Dieser Mehrbyteverbrauch enthält Informationen wie Prüfsumme, Größe und andere zusätzliche Informationen. Wenn wir zu diesem Zeitpunkt kostenlos anrufen, gehen Sie direkt zu den zusätzlichen Informationen, in denen die Adresse gefunden wird und wie viel Block frei sein wird.
quelle
Um die zweite Frage zu beantworten, können Sie die gleiche Technik anwenden,
malloc()
indem Sie einfach die erste Zelle in jedem Array der Größe des Arrays zuweisen. Auf diese Weise können Sie das Array senden, ohne ein zusätzliches Größenargument zu senden.quelle