这是Delphi 2009,因此适用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。
答案 0 :(得分:15)
如果连接字符串,内存管理器将分配更多内存,因为它假定您向其添加越来越多的文本并为将来的连接分配额外的空间。这样,字符串的分配大小远大于使用的大小(取决于使用的内存管理器)。如果使用SetString,则新字符串的分配大小与使用的大小几乎相同。当SRecord字符串超出范围并且其ref-count变为零时,SRecord占用的内存将被释放。因此,您最终会得到字符串所需的最小分配大小。
答案 1 :(得分:-1)
尝试安装内存管理器过滤器(Get / SetMemoryManager),它将对GetMem / FreeMem的所有调用传递给默认内存管理器,但它也执行stats garhtering。您可能会发现两种变体在内存消耗方面都是相同的。
这只是内存碎片。