Der Delphi-Speichermanager hat ein Problem, wenn man ein Array laufend vergrößert.
Hier mal zur Verdeutlichung:
1. Code:
Delphi-Quellcode:
SetLength(100000);
for i := 0 to 100000 - 1 do
a[High(a)] := TMyObject.Create;
2. Code:
Delphi-Quellcode:
a := nil;
for i := 0 to 100000 - 1 do
begin
SetLength(a, Length(a) + 1);
a[High(a)] := TObject.Create;
end;
Das Ergebnis beider Codes ist identisch. Der Speicherverbrauch hingegen nicht. Rein rechnerisch kommt man beim Speicherverbrauch zwar auf diesselben Werte, aber die Realität zeigt etwas anderes:
1. Code: a belegt ca. 4 MB
2. Code: a belegt ca. 120 MB
Das ganze hat mit Speicherlöchern zu tun. So wird beim 1. Code der gesamte Speicher für das Array auf einmal belegt. Beim 2. Code hingegen wird immer wieder vergrößert. Dieses Vergrößern hat zur Folge, dass das neue Array nicht mehr in den alten Speicherbereich passt und somit ein neuer, der das Array aufnehmen kann, reserviert werden muss. Der alte bleibt aber für Windows belegt, da Delphi diesen nicht freigibt, weil er ja Programmintern wieder verwendet werden kann. Nur eben nicht von unserem Array, das zu Groß dafür ist. Da sich aus diesem Grund der Speicherverbrauch der Anwendung immens erhöht, bleibt Windows kein
RAM mehr und es muss auslagern, was die Performance in die Knie zwingt.
Wenn man jedoch auf des "immer wieder Vergrößern" nicht verzichten kann, muss ein anderer Speichermanager her. Ein einfacher, jedoch langsamer ist die nutzung von HeapAlloc, HeapFree und HeapRealloc, die man mit SetMemoryManager durch GetMem, FreeMem und ReallocMem aufrufen kann. Eine Kombination aus Delphi-Speichermanager und den HeapXxx
API Funktionen brachte mir bis jetzt die besten Ergenisse, was Geschwindigkeit und Speicherverbrauch angeht.
Um es aber nicht nur auf Borland zu schieben: Auch der Speichermanager von C/C++ (malloc@msvcrtxx.dll) hat dieses Problem und der stammt von Microsoft.