2014-01-23 2 views
8

Когда я запускаю этот код в XE4, приложение заканчивается использованием ~ 800 МБ.Строки и использование большой памяти

Почему не ближе к 100 МБ?

Использование Ansistring вместо строки не имеет значения.

const 
    N = 10000000; // 10 million 
    M = 10; 
var 
    i,j: integer; 
    s: string; 
    X: array of string; 
begin 
    setlength(X,N); 
    for i:= 1 to N do 
    begin 
    s:= ''; 
    for j:= 1 to M do s:= s+chr(65+random(25)); 
    X[i-1]:= s; 
    end; 
    showmessage('pause'); 
end; 
+0

Мое предположение было бы фрагментации памяти ... но это действительно только предположение. – GabrielF

+0

Да, заменив s: = s + на s [j]: = сбрасывает до 420 МБ, но все равно много пропадает. –

+0

Что делать, если вы делаете 'X: Массив массива [1..10] Char'? Становится ли это лучше? – GabrielF

ответ

11

Строка длины 10 в xe4 использует 34 байт памяти (см DocWiki). 20 байтов для контента, 2 байта для терминатора № 0 и 12 байтов данных управления.

Каждая запись массива является указателем на этот вид памяти. Таким образом, эти 10 миллионов строк в массиве в конечном итоге используют 380 МБ (340 для строк и 40 для элементов массива) памяти как минимум.

+0

Очень хороший ответ. Если вы просто добавляете фрагментацию памяти из-за последовательных конкатенаций строк, она должна быть автономной для последующих посетителей. – GabrielF

+1

@GabrielF 11 символов не должны приводить к заметной фрагментации. Даже при безумном допущении, что кучевый менеджер выделил бы целый мегабайт для строки и переместил бы его в другой мегабайтный слот после добавления каждого символа - это еще один 11 мегабайт, добавленный к сотням MB. Но на самом деле я считаю, что строка s никогда не будет перераспределена во внутреннем цикле. Фрагментация происходит из хранения N коротких строк, а не из M = 10 concatenatiosn на очень короткой строке s –

+0

@ Arioch'The Я не уверен, что понимаю, что вы имеете в виду ... но фрагментация памяти, безусловно, является объяснением для других 400MiB используемая память. Если вы проверите первые несколько комментариев по этому вопросу, вы увидите, что OP уже подтвердил это (и это также было объяснено - например, комментарий KenWhite). – GabrielF

1

Попробуйте

const MaxString = 15; // you said so 

type stringholder = record 
    strict private 
    var Cell: string[ MaxString * SizeOf(Char) div SizeOf(AnsiChar) ]; 
    function GetUS: String; // in xe 4 that is a shortcut to UnicodeString actual type 
    procedure SetUS(const US: string); 
    public 
    property Value: string read GetUS write SetUS; 
    class operator Implicit(const from: string): stringholder; inline; 
    class operator Implicit(const from: stringholder): string; inline; 
    end; 

function stringholder.GetUS: String; 
var i: integer; 
begin 
    i := Ord(Cell[0]); 
    SetLength(Result, i div (SizeOf(Char) div SizeOf(AnsiChar))); 
    if i > 0 then 
    Move(Cell[1], Result[1], i); 
end; 

procedure SetUS(const US: string); 
var i: integer; 
begin 
    If US = '' then begin 
    Cell := ''; // constant here, not US itself 
    Exit; 
    End; 

    i := Length(US); 
    If i > MaxString then raise EInvalidCast.Create('.....'+US); 

    i := i * SizeOf(Char) div SizeOf(AnsiChar) 
    Move(US[1], Cell[1], i); 
    Cell(. 0 .) := AnsiChar(i); 
end; 

class operator stringholder.Implicit(const from: string): stringholder; 
begin 
    Result.Value := from; 
end; 

class operator stringholder.Implicit(const from: stringholder): string; 
begin 
    Result := from.Value; 
end; 


const 
    N = 10000000; // 10 million 
    M = 10; 
var 
    i,j: integer; 
    s: string; 
    X: array of stringholder; 
begin 
    setlength(X,N); 
    for i:= 1 to N do 
    begin 
    s:= ''; 
    for j:= 1 to M do s:= s+chr(65+random(25)); 
    X(. i-1 .) := s; 
    end; 
    showmessage('pause'); 
end; 
Смежные вопросы