2010-09-25 16 views
8

Esto es Delphi 2009, por lo que se aplica Unicode.¿Por qué SetString toma menos memoria en Delphi (con Unicode)?

que tenían un código que estaba cargando cadenas de un búfer en un StringList de la siguiente manera:

 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 

embargo, durante algunas modificaciones, he cambiado la lógica de modo que acabé añadiendo los registros idénticos, sino como una cuerdas derivados por separado y no a través de SetString, es decir

 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 

lo que llamó la atención fue el uso de memoria de la StringList subió de 52 MB a unos 70 MB. Eso fue un aumento de más del 30%.

Para volver a mi menor uso de memoria, me encontré con que tenía que usar SetString para crear la variable de cadena para añadir a mi StringList de la siguiente manera:

 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 

Inspección y comparando S y srecord, están en todos los casos son exactamente iguales. Pero agregar SRecord a MyStringList usa mucha más memoria que agregar S.

¿Alguien sabe qué está pasando y por qué SetString guarda la memoria?


Seguimiento. No pensé que lo haría, pero lo revisé solo para asegurarme.

Ni:

SetLength(SRecord, length(SRecord)); 

ni

Trim(SRecord); 

libera el exceso de espacio. SetString parece ser necesario para hacerlo.

+1

Por cierto, esta es mi pregunta número 100 en StackOverflow. Me gustaría agradecer a la comunidad de programación por la tremenda ayuda que me han brindado para resolver mis problemas de programación en los últimos 2 años. – lkessler

Respuesta

14

Si concatena la cadena, el administrador de memoria asignará más memoria porque asume que le agrega más y más texto y asigna espacio adicional para futuras concatenaciones. De esta forma, el tamaño de asignación de la cadena es mucho mayor que el tamaño utilizado (dependiendo del administrador de memoria utilizado). Si usa SetString, el tamaño de asignación de la nueva cadena es casi el mismo que el tamaño utilizado. Y cuando la cadena SRecord sale del alcance y su recuento de ref resulta cero, se libera la memoria ocupada por SRecord. Así que terminas con el menor tamaño de asignación necesario para tu cadena.

+0

Eso suena plausible @Andreas, pero 30% más de memoria? Mis cadenas son largas y tienen un promedio de 500 caracteres cada una y estoy cargando 100.000 de ellas. Tal vez se necesitan 40 concatenaciones para construir una. Luego la cadena "SRecord" se reutiliza para el siguiente registro, así que espero que el administrador de memoria reutilice el espacio. Podría entender 2 o 3 por ciento de su explicación, pero no 30%. – lkessler

+0

¿Por qué debería el administrador de memoria reutilizar la cadena de SRecord si aún la referencia desde StringList? No puede tener que crear una nueva cadena SRecord para cada uno. –

+0

Esas dos líneas en todos mis ejemplos están cada una en un bucle que se repite una vez para cada registro o 100,000 veces. Al comienzo del ciclo, configuré SRecord: = ''; y luego repite las líneas en el registro y anexa las líneas a SRecord. Entonces, SRecord tiene solo 500 caracteres de longitud. Para el próximo registro, creo que establecer S '' permitirá que el administrador de memoria se limpie. Permítame actualizar el ejemplo para mostrar los bucles. – lkessler

-1

Intente instalar el filtro de administrador de memoria (Get/SetMemoryManager), que pasa todas las llamadas a GetMem/FreeMem al administrador de memoria predeterminado, pero también realiza el control de estadísticas. Probablemente verá que ambas variantes son iguales en consumo de memoria.

Es solo la fragmentación de la memoria.

+0

No lo es; Andreas Hausladen da la respuesta correcta. – himself

+0

@himself Excepto que él está diciendo que la variante de un código es la memoria de sobreasignación, que es una fragmentación de memoria – Alex

+0

La fragmentación se produce cuando la memoria está disponible, solo en bloques pequeños. No es una sobre asignación. – himself

Cuestiones relacionadas