2010-09-25 30 views
8

这是德尔福2009年,所以统一适用。为什么SetString在Delphi中使用更少的内存(使用Unicode)?

我有一些代码,被加载从缓冲器串入的StringList如下:

 var Buffer: TBytes; RecStart, RecEnd: PChar; S: string; 

     FileStream.Read(Buffer[0], Size); 

     repeat 
     ... find next record RecStart and RecEnd that point into the buffer;   

     SetString(S, RecStart, RecEnd - RecStart); 
     MyStringList.Add(S); 
     until end of buffer 

但是,在一些修改,我改变了我的逻辑,这样我结束了加入相同的记录,但作为通过单独的SetString,而不是派生的字符串,即

 var SRecord: string; 

     repeat 
     SRecord := ''; 
     repeat 
      SRecord := SRecord + ... processed line from the buffer; 
     until end of record in the buffer 

     MyStringList.Add(SRecord); 
     until end of buffer 

我注意到的是内存使用的StringList从52 MB上升到大约70 MB。增幅超过30%。

要回到我的更低的内存使用率,我发现我不得不使用的SetString创建字符串变量添加到我的StringList如下:

 repeat 
     SRecord := ''; 
     repeat 
      SRecord := SRecord + ... processed line from the buffer; 
     until end of record in the buffer 

     SetString(S, PChar(SRecord), length(SRecord)); 
     MyStringList.Add(S); 
     until end of buffer 

检查和比较S和SRecord,他们在所有情况都完全一样。但是,增加SRecord到MyStringList使用更多的内存比增加S.

有谁知道这是怎么回事,为什么的SetString节省了内存?


跟进。我不认为会这样,但我只是为了确定。

既不:

SetLength(SRecord, length(SRecord)); 

也不

Trim(SRecord); 

释放多余空间。 SetString似乎需要这样做。

+1

顺便说一句,这是我在StackOverflow上100问题。我只想感谢编程界在过去的两年中为我解决我的编程问题提供了巨大的帮助。 – lkessler 2010-09-25 19:43:46

回答

14

如果字符串连接在一起,因为它假设你添加越来越多的文本它并为未来串连分配额外的空间,内存管理器将分配更多的内存。这样,字符串的分配大小比使用的大小要大得多(取决于使用的内存管理器)。如果使用SetString,则新字符串的分配大小几乎与使用的大小相同。当SRecord字符串超出范围并且其引用计数变为零时,释放SRecord占用的内存。所以你最终得到你的字符串所需的最小分配大小。

+0

这听起来似乎有道理@Andreas,但30%的内存!?我的字符串很长,每个字符平均有500个字符,我正在加载其中的100,000个字符。也许需要40个连接来构建一个。然后“SRecord”字符串被重新用于下一条记录,所以我希望内存管理器可以重用这个空间。我可以从你的解释中理解2%或3%,但不是30%。 – lkessler 2010-09-25 20:57:02

+0

如果仍然从StringList引用它,为什么内存管理器会重用SRecord字符串?它不能为每个创建一个新的SRecord字符串。 – 2010-09-25 21:05:36

+0

我所有例子中的这两行都是循环,每循环记录一次或100,000次。在循环开始时,我设置了SRecord:='';然后循环查找记录中的行并将行追加到SRecord。所以SRecord只有大约500个字符长。对于下一个记录,我认为将S设置为“'将允许内存管理器清理。让我更新示例以显示循环。 – lkessler 2010-09-25 21:13:17

-1

尝试安装的内存管理器过滤器(GET/SetMemoryManager),它传递给GetMem函数/ freemem在所有调用默认的内存管理器,但它也执行统计garhtering。您可能会看到两种变体在内存消耗上都是相同的。

这只是内存碎片。

+0

不是; Andreas Hausladen给出了正确的答案。 – himself 2010-09-27 12:28:50

+0

@himself除了他说一个代码的变体是过度分配内存,这是一个内存碎片 – Alex 2010-09-27 19:29:51

+0

碎片是当内存可用时,只是在小块中。这不是分配。 – himself 2010-09-28 15:55:41

相关问题