Подтвердить что ты не робот

Как рассчитать фактическую память, используемую строковой переменной?

Строки в Delphi, находящиеся в динамической памяти.

Как рассчитать фактическую память (в байтах), используемую переменной string?

Я знаю, что строка должна хранить некоторую дополнительную информацию, по крайней мере, количество ссылок и длину ссылки, но сколько байтов оно использует, кроме символов?

var
  S: string;

Используется Delphi 2010, XE, XE2

4b9b3361

Ответ 1

Макет 32-битного UNICODE DELPHI, взятый из официальной документации Embarcadero, выглядит следующим образом:

UNICODE DELPHI

Обратите внимание, что есть дополнительное поле longint в 64-битной версии для выравнивания по 16 байт. Запись StrRec в 'system.pas' выглядит так:

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

Полезная нагрузка всегда равна 2 * (длина + 1). Накладные расходы составляют 12 или 16 байт, для 32 или 64 бит целей. Обратите внимание, что фактический блок памяти может быть больше необходимого, как определено менеджером памяти.

Наконец, в этом вопросе много неверной информации. По 64-битным целям строки по-прежнему индексируются 32-разрядными целыми знаками.

Ответ 2

Для String в частности, вы можете использовать SysUtils.ByteLength(), чтобы получить длину байта символьных данных, а если не ноль, то прирастите результат на SizeOf(System.StrRec) (который является заголовком перед символьными данными) и SizeOf(Char) (для нуль-терминатора, который не входит в длину), например:

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

С другой стороны, если вы хотите рассчитать размер байта других типов строк, например AnsiString, AnsiString(N) (например, UTF8String), RawByteString и т.д., вам нужно использовать System.StringElementSize() вместо этого, например:

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

В любом случае причина, по которой вы только увеличиваете длину, если строка содержит символы в ней, состоит в том, что пустые строки не занимают никакой памяти вообще, это nil указатели.

Ответ 3

Чтобы ответить на вопрос:

Как рассчитать фактическую память (в байтах), используемую строковой переменной?

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