2010-09-25 7 views
8

Dies ist Delphi 2009, daher gilt Unicode.Warum belegt SetString weniger Speicher in Delphi (mit Unicode)?

Ich hatte einige Code, der Saiten von einem Puffer in einen String geladen wurde, wie folgt:

 var Buffer: TBytes; RecStart, RecEnd: PChar; S: string; 

     FileStream.Read(Buffer[0], Size); 

     repeat 
     ... find next record RecStart and RecEnd that point into the buffer;   

     SetString(S, RecStart, RecEnd - RecStart); 
     MyStringList.Add(S); 
     until end of buffer 

Aber während einigen Modifikationen, ich so meine Logik geändert, dass ich die identischen Aufzeichnungen Zugabe endete, sondern als Strings separat und nicht durch SetString abgeleitet, dh

 var SRecord: string; 

     repeat 
     SRecord := ''; 
     repeat 
      SRecord := SRecord + ... processed line from the buffer; 
     until end of record in the buffer 

     MyStringList.Add(SRecord); 
     until end of buffer 

Was die Speichernutzung des String mir auffiel, war auf etwa 70 MB von 52 MB stiegen. Das war ein Anstieg von über 30%.

Um zu meinem unteren Speicherverbrauch zurück, fand ich hatte ich SetString zu verwenden, um die String-Variable zu erstellen, um meine String wie folgt hinzuzufügen:

 repeat 
     SRecord := ''; 
     repeat 
      SRecord := SRecord + ... processed line from the buffer; 
     until end of record in the buffer 

     SetString(S, PChar(SRecord), length(SRecord)); 
     MyStringList.Add(S); 
     until end of buffer 

prüfen und zu vergleichen S und SRecord, sie sind in alle Fälle genau gleich. Aber das Hinzufügen von SRecord zu MyStringList verwendet viel mehr Speicher als das Hinzufügen von S.

Weiß jemand, was los ist und warum der SetString Speicher spart?


Follow-up. Ich hätte es nicht gedacht, aber ich habe nachgesehen, um sicherzugehen.

Weder:

SetLength(SRecord, length(SRecord)); 

noch

Trim(SRecord); 

gibt den Überschuss Raum. Der SetString scheint dazu erforderlich zu sein.

+1

Übrigens, das ist meine 100ste Frage bei StackOverflow. Ich möchte der Programmierergemeinschaft hier für die enorme Hilfe danken, die sie mir bei der Lösung meiner Programmierprobleme in den letzten zwei Jahren gegeben haben. – lkessler

Antwort

14

Wenn Sie die Zeichenfolge verketten, weist der Speichermanager mehr Speicher zu, da davon ausgegangen wird, dass Sie mehr und mehr Text hinzufügen, und weist zusätzlichen Speicherplatz für zukünftige Verkettungen zu. Auf diese Weise ist die Zuweisungsgröße der Zeichenfolge viel größer als die verwendete Größe (abhängig vom verwendeten Speichermanager). Wenn Sie SetString verwenden, ist die Zuordnungsgröße der neuen Zeichenfolge fast identisch mit der verwendeten Größe. Und wenn die SRecord-Zeichenkette ihren Gültigkeitsbereich verlässt und ihr Ref-Count Null wird, wird der von SRecord belegte Speicher freigegeben. Sie haben also die kleinste benötigte Zuordnungsgröße für Ihre Zeichenfolge.

+0

Das klingt plausibel @Andreas, aber 30% mehr Speicher !? Meine Saiten sind lang und durchschnittlich 500 Zeichen und ich lade 100.000 von ihnen. Vielleicht sind 40 Verkettungen nötig, um eine aufzubauen. Dann wird die Zeichenfolge "SRecord" für den nächsten Datensatz wiederverwendet, so dass ich hoffe, dass der Speichermanager den Speicherplatz wieder verwendet. Ich könnte 2 oder 3 Prozent von Ihrer Erklärung verstehen, aber nicht 30%. – lkessler

+0

Warum sollte der Speichermanager die SRecord-Zeichenfolge wiederverwenden, wenn Sie immer noch von der StringList darauf verweisen. Es kann nicht für jeden eine neue SRecord-Zeichenfolge erstellen. –

+0

Diese beiden Zeilen in allen meinen Beispielen befinden sich jeweils in einer Schleife, die einmal für jeden Datensatz oder 100.000 Mal wiederholt wird. Zu Beginn der Schleife setze ich SRecord: = ''; und dann eine Schleife für die Zeilen im Datensatz und die Zeilen an SRecord anhängen. Also SRecord ist nur etwa 500 Zeichen lang. Für den nächsten Eintrag würde ich denken, dass die Einstellung von S auf '' es dem Speichermanager erlaubt, aufzuräumen. Lassen Sie mich das Beispiel aktualisieren, um die Schleifen zu zeigen. – lkessler

-1

Versuchen Sie, den Speichermanagerfilter (Get/SetMemoryManager) zu installieren, der alle Aufrufe von GetMem/FreeMem an den Standardspeichermanager weiterleitet, aber auch die Daten in der Warteschleife verarbeitet. Sie werden wahrscheinlich sehen, dass beide Varianten im Speicherverbrauch gleich sind.

Es ist nur Speicherfragmentierung.

+0

Es ist nicht; Andreas Hausladen gibt die richtige Antwort. – himself

+0

@himself Außer, dass er sagt, dass die Variante eines Codes den Speicher überschreibt, was eine Speicherfragmentierung ist. – Alex

+0

Fragmentierung ist, wenn der Speicher verfügbar ist, nur in kleinen Blöcken. Es ist keine Übersiedlung. – himself

Verwandte Themen