为什么 SetString 在 Delphi 中占用更少的内存(使用 Unicode)?

发布于 2024-09-25 08:58:35 字数 1522 浏览 4 评论 0原文

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

This is Delphi 2009, so Unicode applies.

I had some code that was loading strings from a buffer into a StringList as follows:

      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

But during some modifications, I changed my logic so that I ended up adding the identical records, but as a strings derived separately and not through SetString, i.e.

      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

What I noticed was the memory use of the StringList went up from 52 MB to about 70 MB. That was an increase of over 30%.

To get back to my lower memory usage, I found I had to use SetString to create the string variable to add to my StringList as follows:

      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

Inspecting and comparing S and SRecord, they are in all cases exactly the same. But adding SRecord to MyStringList uses much more memory than adding S.

Does anyone know what's going on and why the SetString saves memory?


Followup. I didn't think it would, but I checked just to make sure.

Neither:

  SetLength(SRecord, length(SRecord));

nor

  Trim(SRecord);

releases the excess space. The SetString seems to be required to do so.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别靠近我心 2024-10-02 08:58:35

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

If you concatenate the string, the memory manager will allocate more memory because it assumes that you add more and more text to it and allocates additional space for future concatenations. This way the allocation size of the string is much larger than the used size (depending on the used memory manager). If you use SetString, the allocation size of the new string is almost the same as the used size. And when the SRecord string goes out of scope and its ref-count becomes zero, the memory occupied by SRecord is released. So you end up with the smallest needed allocation size for your string.

蓝梦月影 2024-10-02 08:58:35

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

只是内存碎片而已。

Try to install memory manager filter (Get/SetMemoryManager), which passes all calls to GetMem/FreeMem to default memory manager, but it also performs stats garhtering. You'll probably see that both variants are equal in memory consumption.

It's just memory fragmentation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文