Как рассчитать фактическую память, используемую строковой переменной?
Строки в Delphi, находящиеся в динамической памяти.
Как рассчитать фактическую память (в байтах), используемую переменной string
?
Я знаю, что строка должна хранить некоторую дополнительную информацию, по крайней мере, количество ссылок и длину ссылки, но сколько байтов оно использует, кроме символов?
var
S: string;
Используется Delphi 2010, XE, XE2
Ответы
Ответ 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