(Dieser Artikel wurde vorher auf http://www.tgvconsult.de/programmierung/komponenten/8-klasse-tsegmentedmemorystream.html veröffentlicht.)
Update 28.02.2018: Klasse ausgetauscht, auf 10.2 angepaßt.
Die Klasse TSegmentedMemoryStream ist ein TStream-Descendant, der Daten im Heap abspeichert.
Anders als bei TMemoryStream erfolgt die Speicherung nicht als monolithischer Block, sondern es werden Datenblöcke einer zu definierenden Größe allokiert. Die Klasse dient dem Ausschalten der Fragmentierungsproblematik.
TSegmentedMemoryStream kann eingesetzt werden in Anwendungsfällen, wo viel Speicher benötigt wird, z.B. bei der Dateikonvertierung.
Das Problem ist relativ schnell erklärt: jedes Programm verfügt in Windows über einen eigenen virtuellen Adressraum, der vom Virtual Memory Manager auf physischen Speicher bzw. Speicher in derAuslagerungsdatei gemapt wird (dieser Prozess läuft transparent ab). Dieser Adressraum beträgt bei 32-bit-Versionen von Windows 2 GB bzw. 3 GB (mit 4GT-Switch) und bei 64-bit-Versionen zwar mehrere Terrabyte, allerdings mit Einschränkungen:
- 32bit-Anwendung auf 32bit-Windows: 3 GB mit 4GT und IMAGE_FILE_LARGE_ADDRESS_AWARE, ansonsten 2 GB
- 32bit-Anwendung auf 64bit-Windows: 4 GB mit IMAGE_FILE_LARGE_ADDRESS_AWARE, ansonsten 2 GB
- 64bit-Anwendung auf 64bit-Windows: 8 TB mit IMAGE_FILE_LARGE_ADDRESS_AWARE (ab Windows 8.1/Windows 2012 R2 128TB), ansonsten 2 GB
Wird jetzt wahlfrei Speicher allokiert und freigegeben, dann entstehen Speicherlücken und der Speicher wird als frei ausgewiesen. Die Allokation von Speicher erfolgt jedoch immer zusammenhängend, d.h. wenn nur 500 nicht zusammenhängende Blöcke á 1 MB frei sind, dann schlägt die Allokation eines jeden Speicherblocks größer als 1 MB fehl. Werden nun mehrere Allokationen in Folge durchgeführt und wahlfrei wieder freigegeben, z.B. weil mehrere Dateien nacheinander geladen und nicht in der Reihenfolge geschlossen werden, dann entstehen Fragmente, die zusammengenommen zwar ausreichen würden, einzeln jedoch zu klein sind. Durch die Aufteilung des zu allokierenden Speichers in kleine Blöcke kann das effektiv umgangen werden: allokiert werden bei 1 GB nicht mehr ein Block mit 1 GB, sondern z.B. 16384 Blöcke zu 64kB.
Die Klasse übernimmt dabei die Umrechnung der Adressierung, d.h. Positionen im Stream sind fortlaufend und die Klasse ermittelt automatisch die richtigen Speicherblöcke, auf die dann zugegriffen wird.
Weiterführende Informationen:
More on Virtual Memory, Memory Fragmentation and Leaks, and WOW64
Memory Limits for Windows and Windows Server Releases - Memory and Address Space Limits
Memory management under Windows : what your mother didn’t tell you (Bei dem Problem hilft auch TSegmentedMemoryStream nicht, aber das zeigt, daß die beste Blockgröße 64kB ist.)