2012-06-06 15 views
17

Cadenas en ubicación Delphi en memoria dinámica.¿Cómo calcular la memoria real utilizada por la variable de cadena?

Cómo calcular la memoria real (en bytes) utilizada por string variable?

Sé que la cadena debe almacenar cierta información adicional, al menos el recuento de referencias y la longitud, pero ¿cuántos bytes utiliza excepto los caracteres?

var 
    S: string; 

Delphi 2010, XE, XE2 utiliza

+2

La respuesta está documentada en la documentación oficial: http://docwiki.embarcadero.com/RADStudio/en/Unicode_in_RAD_Studio –

+0

@David - Los documentos darán lugar a una conclusión incorrecta en 64 bits, consulte mi comentario en la respuesta de opc0de. –

+0

@Sertac No tengo computadora en este momento. ¿La diferencia entre 32 y 64 bits es simplemente 4 bytes extra de relleno? ¿Entonces la longitud sigue siendo un campo de 32 bits? –

Respuesta

15

El diseño de 32 bits UNICODE DELPHI tomado de la documentación oficial de Embarcadero es así:

UNICODE DELPHI

Tenga en cuenta que hay un adicional campo longint en la versión de 64 bits para la alineación de 16 bytes. El registro en StrRec 'system.pas' se parece a esto:

StrRec = packed record 
{$IF defined(CPUX64)} 
    _Padding: LongInt; // Make 16 byte align for payload.. 
{$IFEND} 
    codePage: Word; 
    elemSize: Word; 
    refCnt: Longint; 
    length: Longint; 
end; 

La carga útil es siempre 2 * (longitud + 1) de tamaño. La sobrecarga es de 12 o 16 bytes, para objetivos de 32 o 64 bits. Tenga en cuenta que el bloque de memoria real puede ser más grande de lo necesario según lo determinado por el administrador de memoria.

Finalmente, ha habido mucha información incorrecta en esta pregunta. En los destinos de 64 bits, las cadenas todavía están indexadas por enteros de 32 bits con signo.

+0

Hubo algunas rarezas, ya sea el RefCount o la longitud estaba limitado a 32 bits y había 32 bits de datos reservados. (No se puede encontrar la referencia en este momento). –

+1

El uso de la memoria real es mayor ya que FastMM redondea el tamaño de la cadena hacia arriba (a 16, IIRC) para un cambio de tamaño de cadena más rápido (s: = s + 'a'). – gabr

+0

Esto se aplica a Delphi pre-Unicode. No es cierto en Unicode Delphi. –

2

Para responder a la pregunta: ¿

cómo calcular de memoria real (en bytes) que utiliza variable de cadena?

MemSize = Overhead + CharSize * (Length + 1) 

CharSize = 1 // for Ansi strings 
CharSize = 2 // for Unicode strings 
Overhead = 8 // for 32 bit strings 
Overhead = 16 // for 64 bit strings 
+0

16 bytes de sobrecarga para una cadena en 64 bits? Eso es bastante: -O Unicode ya duplicó los tamaños de cadena y ahora para cadenas cortas esto empeora aún más ... ¿por qué las cadenas de 64 bits tienen más sobrecarga? No es necesario contar con recuentos y longitudes de referencia de 64 bits ... – jpfollenius

+0

@Smasher - Sin embargo, eso es correcto. En 64 bits hay un LongInt adicional para alinear a 16bytes. –

+0

Esta respuesta es incorrecta. Ver los documentos. –

7

Para String específicamente, puede utilizar SysUtils.ByteLength() para obtener la longitud de bytes de los datos de caracteres, y si no es cero, entonces incrementar el resultado por SizeOf(System.StrRec) (que es la cabecera delante de los datos de caracteres) y SizeOf(Char) (para el terminador nulo que no está incluido en la longitud), por ejemplo:

var 
    S: string; 
    len: Integer; 
begin 
    S := ...; 
    len := ByteLength(s); 
    if len > 0 then Inc(len, SizeOf(StrRec) + SizeOf(Char)); 
end; 

por otro lado, si se quiere calcular el tamaño en bytes de otros tipos de cadenas, como AnsiString, AnsiString(N) (como UTF8String), RawByteString, etc., es necesario utilizar System.StringElementSize() lugar, por ejemplo:

var 
    S: SomeStringType; 
    len: Integer; 
begin 
    S := ...; 
    len := Length(S) * StringElementSize(S); 
    if len > 0 then Inc(len, SizeOf(StrRec) + StringElementSize(s)); 
end; 

En cualquier caso, la razón por la que sólo se incrementará la longitud si la cadena tiene caracteres en ella se debe a que las cadenas vacías no ocupan ningún memoria en absoluto, son nil punteros.

+0

@ Remy: ¿dónde se declara StrRec en Delphi XE? StrRec es desconocido, solo uso 'System.StrRec' – Ampere

+1

'StrRec' se declara en la sección 'implementation' de la unidad' System', por lo que no se puede acceder directamente a él. Tendría que redeclararlo en su propio código si desea usarlo. –

Cuestiones relacionadas