8

这是 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 似乎需要这样做。

4

2 回答 2

15

如果您连接字符串,内存管理器将分配更多内存,因为它假定您向其中添加越来越多的文本并为将来的连接分配更多空间。这样,字符串的分配大小远大于使用的大小(取决于使用的内存管理器)。如果使用 SetString,则新字符串的分配大小与使用的大小几乎相同。并且当 SRecord 字符串超出范围并且它的 ref-count 变为零时,SRecord 占用的内存被释放。因此,您最终得到了字符串所需的最小分配大小。

于 2010-09-25T20:00:52.640 回答
-1

尝试安装内存管理器过滤器 (Get/SetMemoryManager),它将所有对 GetMem/FreeMem 的调用传递给默认内存管理器,但它也执行统计信息收集。您可能会看到两种变体在内存消耗方面是相等的。

这只是内存碎片。

于 2010-09-26T08:26:58.300 回答