2014-01-23 112 views
8

當我在XE4中運行此代碼時,應用程序最終使用〜800 MB。字符串和高內存使用率

爲什麼不接近100 MB?

使用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 MB,但仍浪費了很多。 –

+0

如果你做'X:Char'的Array [1..10]數組怎麼辦?它變得更好嗎? – GabrielF

回答

11

長度爲10的在XE4甲字符串使用的存儲器34個字節(見DocWiki)。內容爲20字節,#0終止符爲2字節,管理數據爲12字節。

每個數組條目都是指向那種內存的指針。因此,陣列中的那一千萬個字符串最終將使用380 MB(對於字符串爲340,對於陣列項爲40)。

+0

非常好的答案。如果由於連續字符串連接而添加內存碎片,它應該對後來的訪問者是自包含的。 – GabrielF

+1

@GabrielF 11個字符不會導致明顯的碎片。即使在瘋狂的假設下,堆管理員會爲該字符串分配一整個兆字節,並且在添加每個字符後將其移動到另一個兆字節的時隙 - 這仍然是數百MB增加的11兆字節。但實際上我相信這些字符串在內部循環中不會重新分配。碎片來自存儲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;