System.Move 和字符串数组

2024-01-26

我正在尝试将一些数组元素(字符串)移动到其他位置。

当我使用System.Move(),FastMM4 报告泄漏。

这是一个显示问题的小片段:

procedure TForm1.Button2Click(Sender: TObject);
type
  TArrayOfStr = array of string;
const
  Count1 = 100;
  String1 = 'some string ';  {space at end}
var
  Array1: TArrayOfStr;
  Index1: Integer;
begin
  SetLength(Array1, Count1);
  Index1 := 0;
  while Index1 < Count1 do begin
    Array1[Index1] := String1 + IntToStr(Index1);
    Inc(Index1);
  end;
  System.Move(Array1[0], Array1[3], 2 * SizeOf(string)); {move 2 cells from cell 0 to cell 3}
  ShowMessage(Array1[3]);
end;

这可能与SizeOf(String)但我不知道是什么。

有人可以帮我消除泄漏吗?


Issues
您遇到的问题与字符串的引用计数有关。

  1. Leaks
    If您要覆盖的区域中已经有一个字符串,这些字符串将不会被释放。这些是您报告的泄漏。

  2. 潜在的访问违规
    您复制字符串指针,但不会增加字符串的引用计数。如果原始字符串由于超出范围而被破坏,这将导致访问冲突。这是一个非常微妙的错误,会在您最意想不到的时候咬您。

最佳解决方案
让 Delphi 进行复制,然后所有内部簿记都会正确完成,这要简单得多。

  {move 6 from cell 1 to cell 3}
  System.Move(Array1[0], Array1[3], 2 * SizeOf(string)); 
  //This does not increase the reference count for the string;
  //leading to problems at cleanup.

  Array1[3]:= Array1[0];
  Array1[4]:= Array1[1];  //in a loop obviously :-)
  //this increases the reference count of the string.

请注意,Delphi 不会复制字符串,它只是复制指针并根据需要增加引用计数。它还根据需要释放任何字符串。

黑客解决方案
您应该先手动清理该区域。
Using

for i:= start to finish do Array1[i]:= '';

这个解决方案可怕的黑客的下一部分是手动增加您复制的字符串的引用计数。
See: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats#Long_String_Types http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats#Long_String_Types

procedure IncreaseRefCount(const str: string; HowMuch: integer = 1);
var
  Hack: PInteger;
begin
  Hack:= pointer(str);
  Dec(Hack,2); //get ref count
  Hack^:= AtomicIncrement(Hack^,HowMuch);
end;

  System.Move(Array1[0], Array1[3], 2 * SizeOf(string)); 
  IncreaseRefCount(Array1[3]);
  .... do this for every copied item.

请注意,如果您从数组外部的某个位置获取字符串,则此 hack 不是完全线程安全的。

但是,如果您确实需要速度,那么这可能是使副本性能提高 2% 的解决方案。

Warning
不要使用此代码手动减少引用计数,您将遇到线程安全问题!

需要速度
仅仅处理几个字符串不太可能导致速度变慢。
如果您坚持使用托管字符串,则无法解决清理问题。
另一方面,引用计数的开销实际上并没有那么糟糕,所以我怀疑缓慢的原因在于其他地方;在我们看不到的地方,因为您没有告诉我们您的问题。

我建议你问一个新问题,解释你想要做什么,为什么以及缓慢对你造成了伤害。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

System.Move 和字符串数组 的相关文章

  • 如何在c中的某个位置终止字符指针?

    我试图通过设置空终止符来终止 c 中的字符指针 在特定位置 例如 如果我有一个 char 指针 char hi hello 我希望它是 hell 通过设置o为空 我尝试过使用 strcpy 来执行此操作 例如 strcpy hi 4 0 但
  • Delphi 2010 - 从 XML 文档解码 Base64 编码图像

    我正在尝试从应用程序中的 XML 文档解码 base64 编码的 EMF 图像并将其呈现在屏幕上 但是 它似乎从未出现 如果我将 XML 文档中的数据复制 粘贴到 Notepad 中并使用Base64 Decode选项并将文件另存为 emf
  • 生成逗号分隔值

    假设我有一个字符串集合 foo bar xyz 我想从列表中生成一个逗号分隔的值 如下所示 foo bar xyz 请注意末尾缺少 我知道有多种方法可以生成此内容 使用 for 循环和 string Format 或 StringBuild
  • 对象的引用计数

    在我的代码中 我使用一个小的数据存储类 它是在不同的地方创建的 为了避免内存泄漏并简化事情 我想使用引用计数 所以我这样做了 type TFileInfo class TInterfacedObject IInterface 并删除了我对
  • 如何用不同的颜色绘制选定的列表框项目?

    是否可以更改 TListBox 中的项目选择焦点颜色和文本颜色 当项目中未启用主题或列表框样式设置为所有者绘制时 项目周围的选择将被涂成蓝色 我相信这是由系统的外观设置全局定义的 我想将所选项目的颜色更改为自定义颜色 举个例子 结果会是这样
  • 如何在Delphi中显示Vista风格的气球提示?

    在输入验证时 我使用气球提示而不是消息框 我的问题是 在 Vista 上 它们具有带圆角的旧 XP 样式 而不是较新的矩形外观 我尝试使用 CreateWindowEx 创建它们并且tooltips class32或使用 SendMessa
  • 如何使 StringGrid 的列适合网格的宽度?

    我已经寻找解决方案很长时间了 但没有任何运气 有谁知道一个简单的方法来做到这一点 例如 我想拉伸网格的第二列以适应网格的宽度 Use the ColWidths财产 像这样 with StringGrid1 do ColWidths 1 C
  • 奇怪的跨线程 UI 错误

    我正在编写一个 WinForms 应用程序 它有两种模式 控制台或 GUI 同一解决方案中的三个项目 一个用于控制台应用程序 一个用于 UI 表单 第三个用于保存两个界面也将连接的逻辑 控制台应用程序运行绝对流畅 保存用户选择的模型 它有一
  • 如何在iOS的Delphi程序中使用IPv6协议

    我尝试在我的移动程序中使用 IPv6 协议 我的服务器位于 NAT 后面的 LAN 内 在服务器上我使用IP端口3000 我已经组织了从路由器端口 45500 到服务器端口 3000 的虚拟服务器 端口转发 在服务器上 我运行 ipconf
  • 静态字符串文字表?

    在 C 中创建全局静态字符串表的正确方法是什么 我所说的 全局 是指 可从包含标头的任何文件中使用 但不是某些运行时创建的单一对象的一部分 我所说的 静态 是指 尽可能少地设置运行时间 只读内存页中的数据 每个应用程序只有 1 个数据实例
  • 删除Android所有语言中的字符串

    我有一个包含多个翻译的应用程序 我想删除一些字符串 我怎样才能重构并删除它们一次 例如在默认情况下strings xml文件并自动将删除传播到其他翻译的其他 strings xml 文件 您可以通过 Android Studio 中的 翻译
  • 在 Delphi 或 C++ Builder 中使用 Chromium Edge WebView2 [重复]

    这个问题在这里已经有答案了 既然 Microsoft Chromium Edge 已经最终确定 是否可以在 Delphi 或 C Builder 中使用它 据我了解 它是基于WebView2成分 是否有一个组件 例如TWebView2或者E
  • 将图像加载到 TImageList 并读取它们?

    我试图通过将 jpg 转换为 bmp 然后将其保存到 imagelist1 来将 jpg 加载到图像列表中 从上到下的代码片段 Selectdir 有效 fileexists 部分有效 这用于加载文件夹中的所有图像 所有图像都以 0 jpg
  • 如何比较枚举类型集

    从某个时刻开始 我厌倦了编写设定条件 and or 因为对于更多的条件或更长的变量名 重新编写会变得笨拙且烦人 所以我开始写助手这样我就可以写ASet ContainsOne ceValue1 ceValue2 代替 ceValue1 in
  • 用于字数计算的 Swift String 中的字数

    我想做一个程序来找出字符串中有多少个单词 用空格 逗号或其他字符分隔 然后把总数加起来 我正在制作一个平均计算器 所以我想要数据总数 然后将所有单词相加 update Xcode 10 2 x Swift 5 或更高版本 使用基础方法enu
  • 阻止 IDE 自动添加使用单位

    我正在将 Lazarus 项目转移到德尔福西雅图 Lazarus 项目依赖于 40 多个单元 包括控件 并具有多种应用程序 在所有项目的使用条款中 他们使用了以下内容 uses Classes SysUtils Forms Controls
  • 为什么 Delphi 中的 ADO Next 记录处理速度变慢?

    我有一个多年前开发的 Delphi 4 程序 它使用Opus 直接访问 http sourceforge net projects directaccess 按顺序搜索 Microsoft Access 数据库并检索所需的记录 Delphi
  • Javascript:删除字符串标点符号并拆分成单词?

    抱歉 如果之前有人问过这个问题 但我正在尝试从这样的字符串中获取单词数组 Exclamation Question Quotes Apostrophe Wasn t Couldn t Didn t 该数组应该看起来像这样 exclamati
  • 返回类型时 c_str() 与 data()

    在C 11之后 我想到了c str and data 同等地 https stackoverflow com questions 194634 string c str vs data C 17 为后者引入了一个重载 它返回一个非常量指针
  • 如何从 JavaScript 中的字符串中删除空白字符?

    如何从 JavaScript 中的字符串中删除空白字符 修剪很容易 但我不知道如何将它们从inside字符串 例如 222 334 gt 222334 您可以使用正则表达式 如下所示来替换所有空格 var oldString 222 334

随机推荐