【问题标题】:delphi call delphi dll memory leak caused by pchardelphi调用delphi dll内存泄漏导致pchar
【发布时间】:2015-12-27 16:07:46
【问题描述】:

让我们来了解一下 dll。

如果要将字符串传递给 dll 调用,则必须使过程输入 PChar。否则你会得到数据curroption。

所以我们说我们的dll有

  procedure LookPchar(pfff:Pchar);stdCall;External 'OutDll.dll';

这很好。现在让我们看看我们在 dll dpr 中声明了什么:

  procedure LookPchar(pfff:Pchar);
  begin
    with TForm1.Create(nil) do
    try
      show;
      FireDacConnection.ConnectionName := (Copy(pfff,1,100));
    finally
      free;
    end;

  end;
  exports LookPchar;

好吧,在 Dll 中,我们有一个 Form,其中有一个 FireDacConnection,但其中的任何组件或对象都可以完成这项工作。

问题是这个PChar被释放了两次,导致内存泄漏。我找不到在不导致内存泄漏的情况下通过 PChar 的方法。

你可以用fastmm,我用eurukalog,它写

|+Leak #2: Type=UnicodeString: Ref count - 1, Content: "\r\n";全部的 大小=18;计数=1 |

为什么 Unicode 字符串的 Ref 计数为 -1?如何预防?如何正确传递 Unicode 字符串?

我尝试了什么: 将其作为 const 传递。 复制它(如示例和使用 strpcopy 和 strcopy) 使用局部变量来保存 PChar 的副本。

编辑: 添加调用代码:

var
  ConnectionName:WideString;
begin
  ConnectionName := 'This Is My String';
  LookPChar(PChar(ConnectionName));
end;

添加泄漏日志转储

|+Leak #2: Type=UnicodeString: Ref count - 1, Content: "\r\n";总大小=18;计数=1 | |------------------------------------------------- -------------------------------------------------- --------------------------------------------------| |00000002|04 |00000000|01D79D9C|outDll.dll|00009D9C|系统
| |_NewUnicodeString |23897[6] | |00000002|04 |00000000|008A11BC|myapp.exe |004A11BC|调用者
|TForm2 |Button4单击 |66[2] | |00000002|04 |00000000|00641C13|myapp.exe |00241C13|Vcl.Controls |TControl |点击|7348[9] | |00000002|04 |00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl |WndProc |10038[153] | |00000002|04 |00000000|0065B71C|myapp.exe |0025B71C|Vcl.StdCtrls |TButtonControl|WndProc |5163[13] | |00000002|04 |00000000|006462D7|myapp.exe |002462D7|Vcl.Controls | |DoControlMsg |10107[12] | |00000002|04 |00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl |WndProc |10038[153] | |00000002|04 |00000000|0070B240|myapp.exe |0030B240|Vcl.Forms
|TCustomForm |WndProc |4427[206] | |00000002|04 |00000000|006457AC|myapp.exe |002457AC|Vcl.Controls |TWinControl |MainWndProc |9750[3] | |00000002|04 |00000000|004F7614|myapp.exe |000F7614|系统.类| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (可能的 间隙fnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (可能 GetThreadDesktop+210)| | |00000002|03
|00000000|76816DE8|user32.dll |00016DE8|USER32 |
| (可能 GetThreadDesktop+389) | | |00000002|03
|00000000|76816E49|user32.dll |00016E49|USER32 |
| (可能 GetThreadDesktop+486)| | |00000002|03
|00000000|77420107|ntdll.dll |00010107|ntdll |
|KiUserCallbackDispatcher | | |00000002|03
|00000000|768196D0|user32.dll |000196D0|USER32 |
|发送信息W | | |00000002|03
|00000000|71AB459B|comctl32.dll |000A459B|comctl32 |
|加载图标度量 | | |00000002|03
|00000000|71AB45FE|comctl32.dll |000A45FE|comctl32 |
|加载图标度量 | | |00000002|03
|00000000|71AB4488|comctl32.dll |000A4488|comctl32 |
|加载图标度量 | | |00000002|03
|00000000|768162F7|user32.dll |000162F7|USER32 |
| (可能有间隙fnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (可能 GetThreadDesktop+210)| | |00000002|03
|00000000|76820D32|user32.dll |00020D32|USER32 |
| (可能的 GetClientRect+192)| | |00000002|03
|00000000|76820D56|user32.dll |00020D56|USER32 |
|CallWindowProcW | | |00000002|04
|00000000|00646282|myapp.exe |00246282|Vcl.Controls |TWinControl
|默认处理程序 |10079[30] | |00000002|04
|00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl
|WndProc |10038[153] | |00000002|04
|00000000|0065B71C|myapp.exe |0025B71C|Vcl.StdCtrls |TButtonControl|WndProc |5163[13] | |00000002|04 |00000000|004F7614|myapp.exe |000F7614|系统.类| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (可能的 间隙fnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (可能 GetThreadDesktop+210)| | |00000002|03
|00000000|768177CE|user32.dll |000177CE|USER32 |
| (可能 CharPrevW+314) | | |00000002|03
|00000000|76817893|user32.dll |00017893|USER32 |

|DispatchMessageW | |

抱歉不清楚,我不知道如何在 stackoverflow 编辑器中保留标签。

【问题讨论】:

  • 向/从 dll 传递字符串的最简单方法是使用 WideString 参数类型。
  • 保存字符串引用的参数在 dll 中被访问之前超出范围。对Show 的调用没有阻塞。您需要在调用 Show 之前制作字符串的本地副本。
  • @user246408 结果相同,引用计数-1
  • @LURD 是 "FireDacConnection.ConnectionName := (Copy(pfff,1,100));"不是你建议的?
  • 由于Show没有阻塞,你需要在调用Show之前复制字符串。

标签: delphi memory-leaks delphi-xe7 pchar


【解决方案1】:

Copy(pfff,1,100) 很奇怪。您可以直接使用pfff 并让编译器自动将指针转换为空终止字符数组到字符串。

FireDacConnection.ConnectionName := pfff;

在致电Show 之前这样做肯定是有意义的。你显示一个无模式的表单,然后设置连接名称,然后释放表单,这当然看起来很奇怪。事实上,即使在 DLL 中显示一个表单也看起来很奇怪。

也就是说,这不是您的问题的原因。代码泄漏的唯一解释是调用约定不匹配,或者调用站点出现错误。传递PChar,并像您一样复制一份,不会泄漏。

实现中的调用约定似乎是register。 DLL 中的声明应该是:

procedure LookPchar(pfff:Pchar); stdcall;

或者你没有在 DLL 代码中显示stdcall

您可能在呼叫现场犯了一个错误。也许泄漏就在那里。我们看不到那个代码。

查看您的各种编辑,FastMM 报告了问题中的任何代码都没有产生的泄漏。您需要先隔离问题,然后才能解决它。这是你的下一步。

使用PChar 可以输入。在另一个方向,从被调用者到调用者,有很多选择,但你没有在这里问过。关于这个话题有很多问题。

【讨论】:

  • dll 中的 stdcall 应该是什么?你能在代码上显示吗?或提供线路?(请与注册相同)。
  • 关注这个:tutorialspoint.com/dll/dll_delphi_example.htm 并添加了 stdcall;到dll中的过程。并添加了索引 1;到出口。还是一样的错误。
  • 你似乎在挣扎。随意尝试的东西。对任何事情都没有清晰的认识。回归本源。忘记形式和连接。尝试将 PChar 成功传递给 DLL。
  • @david-hefferman 仅将 PChar 传递给 dll,并执行 showmessage,不会出现内存泄漏或数据损坏。当它被传递给对象时,引用计数开始起作用并造成损害。
  • PChar 上没有引用计数。除了调用约定和对 Copy 的奇怪使用之外,您提供的代码基本上没问题。错误在其他地方。
猜你喜欢
  • 2014-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多