Es gibt viele Verfahren , um Speicher in Windows - Umgebung zuweisen, wie VirtualAlloc
, HeapAlloc
, malloc
, new
.
Was ist also der Unterschied zwischen ihnen?
Antworten:
Jede API ist für unterschiedliche Zwecke bestimmt. Jeder erfordert auch, dass Sie die richtige Freigabe- / Freigabefunktion verwenden, wenn Sie mit dem Speicher fertig sind.
Eine Windows-API auf niedriger Ebene, die viele Optionen bietet, aber hauptsächlich für Personen in bestimmten Situationen nützlich ist. Kann nur Speicher in größeren Blöcken zuweisen (bearbeiten: nicht 4 KB). Es gibt Situationen, in denen Sie es brauchen, aber Sie werden wissen, wann Sie sich in einer dieser Situationen befinden. Eine der häufigsten ist, wenn Sie den Speicher direkt mit einem anderen Prozess teilen müssen. Verwenden Sie es nicht für die allgemeine Speicherzuweisung. Verwenden Sie VirtualFree
ausplanen.
Weist die gewünschte Speichergröße zu, nicht in großen Blöcken als VirtualAlloc
. HeapAlloc
weiß, wann es anrufen muss VirtualAlloc
und erledigt dies automatisch für Sie. Wie malloc
, ist aber nur Windows und bietet ein paar weitere Optionen. Geeignet zum Zuweisen allgemeiner Speicherblöcke. Einige Windows-APIs erfordern möglicherweise, dass Sie dies verwenden, um Speicher zuzuweisen, den Sie an sie übergeben, oder den Begleiter verwenden HeapFree
, um Speicher freizugeben, den sie an Sie zurückgeben.
Die C-Methode zum Zuweisen von Speicher. Ziehen Sie dies vor, wenn Sie in C anstatt in C ++ schreiben und möchten, dass Ihr Code auch auf Unix-Computern funktioniert, oder wenn jemand ausdrücklich sagt, dass Sie ihn verwenden müssen. Initialisiert den Speicher nicht. Geeignet für die Zuweisung allgemeiner Speicherblöcke, wie z HeapAlloc
. Eine einfache API. Verwenden Sie free
ausplanen. Visual C ++ - malloc
Aufrufe HeapAlloc
.
Die C ++ - Methode zum Zuweisen von Speicher. Ziehen Sie dies vor, wenn Sie in C ++ schreiben. Es legt auch ein Objekt oder Objekte in den zugewiesenen Speicher. Verwenden Sie delete
diese Option, um die Zuordnung aufzuheben (oder delete[]
für Arrays). Visual Studio new
ruft HeapAlloc
die Objekte auf und initialisiert sie dann möglicherweise, je nachdem, wie Sie sie aufrufen.
Wenn Sie in neueren C ++ - Standards (C ++ 11 und höher) manuell verwenden müssen delete
, machen Sie es falsch und sollten stattdessen einen intelligenten Zeiger wie unique_ptr
verwenden. Ab C ++ 14 gilt das Gleiche new
(ersetzt durch Funktionen wie make_unique()
).
Es gibt auch einige andere ähnliche Funktionen SysAllocString
, von denen Ihnen möglicherweise mitgeteilt wird, dass Sie sie unter bestimmten Umständen verwenden müssen.
VirtualAlloc
ist eine spezielle Zuordnung des VM-Systems (Virtual Memory) des Betriebssystems. Zuweisungen im VM-System müssen mit einer Zuordnungsgranularität erfolgen, die (die Zuordnungsgranularität) von der Architektur abhängt. Die Zuweisung im VM-System ist eine der grundlegendsten Formen der Speicherzuweisung. VM-Zuweisungen können verschiedene Formen annehmen. Der Speicher ist nicht unbedingt dediziert oder wird physisch im RAM gesichert (obwohl dies möglich ist). Die VM-Zuweisung ist in der Regel eine spezielle Zuweisung, entweder aufgrund der Zuweisung
HeapAlloc
ist im Wesentlichen was malloc
und new
beide nennen schließlich. Es ist so konzipiert, dass es unter vielen verschiedenen Szenarien einer Allzweckzuweisung sehr schnell und verwendbar ist. Es ist der "Haufen" im klassischen Sinne. Heaps werden tatsächlich von a eingerichtet VirtualAlloc
. Dies wird verwendet, um zunächst Speicherplatz vom Betriebssystem zu reservieren. Nachdem der Speicherplatz durch initialisiert wurde VirtualAlloc
, werden verschiedene Tabellen, Listen und andere Datenstrukturen konfiguriert, um den Betrieb des HEAP aufrechtzuerhalten und zu steuern. Ein Teil dieser Operation besteht in der dynamischen Dimensionierung (Vergrößerung und Verkleinerung) des Heaps, der Anpassung des Heaps an bestimmte Verwendungszwecke (häufige Zuweisungen einiger Größen) usw.
new
und malloc
sind etwas gleich, malloc
ist im wesentlichen ein exakter Aufruf in HeapAlloc( heap-id-default )
; new
kann jedoch [zusätzlich] den zugewiesenen Speicher für C ++ - Objekte konfigurieren . Für ein bestimmtes Objekt speichert C ++ für jeden Aufrufer vtables auf dem Heap. Diese vtables sind Weiterleitungen für die Ausführung und Teil dessen, was C ++ seine OO-Eigenschaften wie Vererbung, Funktionsüberladung usw. verleiht.
Einige andere gängige Zuweisungsmethoden wie _alloca()
und _malloca()
sind stapelbasiert . FileMappings werden wirklich VirtualAlloc
bestimmten Bit-Flags zugewiesen und mit diesen gesetzt, die diese Zuordnungen als vom Typ kennzeichnen FILE
.
Meistens sollten Sie den Speicher so zuweisen, dass er mit der Verwendung dieses Speichers übereinstimmt;). new
in C ++ malloc
für C VirtualAlloc
für massive oder IPC-Fälle.
*** Beachten Sie, dass große Speicherzuweisungen, die von vorgenommen HeapAlloc
werden, tatsächlich VirtualAlloc
nach einer gewissen Größe ausgeliefert werden (ein paar hundert k oder 16 MB oder etwas, das ich vergessen habe, aber ziemlich groß :)).
*** BEARBEITEN Ich habe kurz auf IPC hingewiesen und VirtualAlloc
es gibt auch etwas sehr Ordentliches an einem verwandten, VirtualAlloc
das keiner der Antwortenden auf diese Frage besprochen hat.
VirtualAlloc
Ex ist das, was ein Prozess verwenden kann, um Speicher in einem Adressraum eines anderen Prozesses zuzuweisen . In der Regel wird dies in Kombination verwendet , um die Remote-Ausführung im Kontext eines anderen Prozesses über CreateRemoteThread abzurufen (ähnlich wie CreateThread
der Thread nur im anderen Prozess ausgeführt wird).
Es ist sehr wichtig, die Unterscheidung zwischen Speicherzuweisungs-APIs (in Windows) zu verstehen, wenn Sie eine Sprache verwenden möchten, die eine Speicherverwaltung erfordert (wie C oder C ++). IMHO lässt sich dies am besten anhand eines Diagramms veranschaulichen:
Beachten Sie, dass dies eine sehr vereinfachte, Windows-spezifische Ansicht ist.
Um dieses Diagramm zu verstehen, gilt: Je höher eine Speicherzuweisungsmethode im Diagramm ist, desto höher ist die Implementierung, die sie verwendet. Aber fangen wir von unten an.
Es bietet alle Speicherreservierungen und -zuordnungen für das Betriebssystem sowie Unterstützung für Dateien mit Speicherzuordnung , gemeinsam genutzten Speicher , Kopier- und Schreibvorgänge usw. Es ist nicht direkt über den Benutzermodus-Code zugänglich, daher überspringe ich hier.
Dies sind die APIs der niedrigsten Ebene, die im Benutzermodus verfügbar sind . Die VirtualAlloc
Funktion ruft im Grunde ZwAllocateVirtualMemory das wiederum macht eine schnelle syscall zu ring0
weiterer Verarbeitung an den Kernel - Speicher - Manager zu verbannen. Dies ist auch die schnellste Methode, um einen Block neuen Speichers von allen im Benutzermodus verfügbaren zu reservieren / zuzuweisen.
Aber es kommt mit zwei Hauptbedingungen:
Es werden nur Speicherblöcke zugewiesen, die an der Systemgranularitätsgrenze ausgerichtet sind.
Es werden nur Speicherblöcke mit der Größe zugewiesen, die das Vielfache der Systemgranularität ist.
Was ist diese Systemgranularität ? Sie können es erhalten, indem Sie GetSystemInfo aufrufen . Es wird als dwAllocationGranularity
Parameter zurückgegeben. Sein Wert ist implementierungs- (und möglicherweise hardwarespezifisch), aber auf vielen 64-Bit-Windows-Systemen ist er auf 0x10000
Bytes oder festgelegt 64K
.
Das alles bedeutet also, dass Sie beim Zuweisen nur einen 8-Byte-Speicherblock sagen mit VirtualAlloc
:
void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Wenn erfolgreich, pAddress
wird an der 0x10000
Bytegrenze ausgerichtet . Und obwohl Sie nur 8 Bytes angefordert haben, ist der tatsächliche Speicherblock, den Sie erhalten, der gesamte page
(oder etwa 4K
Bytes. Die genaue Seitengröße wird im dwPageSize
Parameter zurückgegeben.) Darüber hinaus der gesamte Speicherblock Spanning 0x10000
Bytes (oder 64K
in den meisten Fällen) von stehen für weitere Zuordnungen pAddress
nicht zur Verfügung. In gewisser Weise könnten Sie durch Zuweisen von 8 Bytes auch nach 65536 fragen.
Die Moral der Geschichte hier besteht also nicht darin, VirtualAlloc
generische Speicherzuordnungen in Ihrer Anwendung zu ersetzen . Es muss für ganz bestimmte Fälle verwendet werden, wie dies mit dem folgenden Heap geschieht . (Normalerweise zum Reservieren / Zuweisen großer Speicherblöcke.)
Eine VirtualAlloc
falsche Verwendung kann zu einer starken Speicherfragmentierung führen.
Kurz gesagt, die Heap- Funktionen sind im Grunde genommen ein Wrapper für VirtualAlloc
Funktionen. Andere Antworten hier liefern ein ziemlich gutes Konzept dafür. Ich werde hinzufügen, dass in einer sehr vereinfachten Ansicht die Art und Weise, wie Heap funktioniert, folgende ist:
HeapCreate
reserviert einen großen Block virtuellen Speichers durch VirtualAlloc
internen Aufruf (oder ZwAllocateVirtualMemory
um genau zu sein). Außerdem wird eine interne Datenstruktur eingerichtet, mit der weitere kleinere Zuordnungen innerhalb des reservierten Blocks des virtuellen Speichers verfolgt werden können.
Anrufe zu HeapAlloc
und HeapFree
nicht wirklich zuordnen / frei , alle neuen Speicher (es sei denn natürlich die Anforderung hinaus , was bereits in reserviert ist HeapCreate
) , sondern sie Meter aus (oder commit
) ein zuvor reservierten großen Teil, indem sie sie in kleinere Speicherblöcke zu sezieren , dass ein Benutzer fordert.
HeapDestroy
Aufrufe VirtualFree
, die tatsächlich den virtuellen Speicher freigeben.
All dies macht Heap- Funktionen zu perfekten Kandidaten für generische Speicherzuordnungen in Ihrer Anwendung. Es eignet sich hervorragend für Speicherzuordnungen beliebiger Größe. Ein kleiner Preis für die Bequemlichkeit der Heap- Funktionen besteht jedoch darin, dass sie einen geringen Overhead verursachen, VirtualAlloc
wenn größere Speicherblöcke reserviert werden.
Eine weitere gute Sache bei Heap ist, dass Sie nicht wirklich einen erstellen müssen. Es wird in der Regel für Sie erstellt, wenn Ihr Prozess beginnt. Sie können also darauf zugreifen, indem Sie die Funktion GetProcessHeap aufrufen .
Ist ein sprachspezifischer Wrapper für die Heap- Funktionen. Im Gegensatz zu HeapAlloc
, HeapFree
werden usw. Diese Funktionen arbeiten nicht nur , wenn Ihr Code für Windows kompiliert wird, sondern auch für andere Betriebssysteme (wie Linux, etc.)
Dies ist eine empfohlene Methode zum Zuweisen / Freigeben von Speicher, wenn Sie in C programmieren. (Es sei denn, Sie codieren einen bestimmten Gerätetreiber im Kernelmodus.)
Kommen Sie als hochrangige (gut für C++
) Speicherverwaltungsoperatoren. Sie sind spezifisch für die C++
Sprache und wie malloc
für C
sind auch die Wrapper für die heap
Funktionen. Sie haben auch eine ganze Reihe ihres eigenen Codes, der sich mit der C++
spezifischen Initialisierung von Konstruktoren, der Freigabe von Destruktoren, dem Auslösen einer Ausnahme usw. befasst.
Diese Funktionen sind eine empfohlene Methode zum Zuweisen / Freigeben von Speicher und Objekten, wenn Sie programmieren C++
.
Zuletzt möchte ich einen Kommentar zu dem abgeben, was in anderen Antworten über die Verwendung VirtualAlloc
zum Teilen des Speichers zwischen Prozessen gesagt wurde . VirtualAlloc
an sich erlaubt es nicht, seinen reservierten / zugewiesenen Speicher mit anderen Prozessen zu teilen. Dazu muss eine CreateFileMapping
API verwendet werden, die einen benannten virtuellen Speicherblock erstellen kann, der für andere Prozesse freigegeben werden kann. Es kann auch eine Datei auf der Festplatte für den Lese- / Schreibzugriff dem virtuellen Speicher zuordnen. Aber das ist ein anderes Thema.
In Umrissen:
VirtualAlloc, HeapAlloc usw. sind Windows-APIs, die Speicher verschiedener Typen direkt vom Betriebssystem zuweisen. VirtualAlloc verwaltet Seiten im virtuellen Windows-Speichersystem, während HeapAlloc von einem bestimmten Betriebssystem-Heap aus zuweist. Ehrlich gesagt ist es unwahrscheinlich, dass Sie jemals einen von ihnen verwenden müssen.
malloc ist eine Standard-C- (und C ++) Bibliotheksfunktion, die Ihrem Prozess Speicher zuweist. Bei Implementierungen von malloc wird normalerweise eine der Betriebssystem-APIs verwendet, um beim Start Ihrer App einen Speicherpool zu erstellen und diesen dann zuzuweisen, wenn Sie malloc-Anforderungen stellen
new ist ein Standard-C ++ - Operator, der Speicher zuweist und dann Konstruktoren in diesem Speicher entsprechend aufruft. Es kann in Form von Malloc oder in Bezug auf die Betriebssystem-APIs implementiert werden. In diesem Fall wird beim Start der Anwendung normalerweise auch ein Speicherpool erstellt.
VirtualAlloc
===> sbrk()
unter UNIX
HeapAlloc
====> malloc()
unter UNIX
VirtualAlloc
=> Wird direkt in den virtuellen Speicher zugewiesen, reservieren / festschreiben Sie in Blöcken. Dies ist ideal für große Zuordnungen, z. B. große Arrays.
HeapAlloc
/ new
=> ordnet den Speicher auf dem Standardheap (oder einem anderen von Ihnen erstellten Heap) zu. Dies wird pro Objekt zugewiesen und eignet sich hervorragend für kleinere Objekte. Der Standard-Heap ist serialisierbar und verfügt daher über eine garantierte Thread-Zuweisung (dies kann in Hochleistungsszenarien zu Problemen führen, weshalb Sie Ihre eigenen Heaps erstellen können).
malloc
=> verwendet den C-Laufzeitheap, ähnlich wie HeapAlloc
bei Kompatibilitätsszenarien.
Kurz gesagt, der Heap ist nur ein Teil des virtuellen Speichers, der von einem Heap-Manager gesteuert wird (und nicht von einem virtuellen Rohspeicher).
Das letzte Modell in der Speicherwelt sind Dateien mit Speicherzuordnung. Dieses Szenario eignet sich hervorragend für große Datenmengen (wie große Dateien). Dies wird intern verwendet, wenn Sie eine EXE-Datei öffnen (die EXE-Datei wird nicht in den Speicher geladen, sondern nur eine Speicherzuordnungsdatei erstellt).