delphi调用delphi由pchar引起的dll内存泄漏
delphi call delphi dll memory leak caused by pchar
所以让我们来看看 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"; Total
size=18; Count=1 |
为什么 Unicode 字符串的引用计数为 -1?如何预防?如何正确传递Unicode字符串?
我尝试了什么:
将其作为常量传递。
复制它(如示例和 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"; Total size=18; Count=1 |
|-----------------------------------------------------------------------------------------------------------------------------------------| |00000002|04 |00000000|01D79D9C|outDll.dll|00009D9C|System
| |_NewUnicodeString |23897[6] |
|00000002|04 |00000000|008A11BC|myapp.exe |004A11BC|Caller
|TForm2 |Button4Click |66[2] |
|00000002|04 |00000000|00641C13|myapp.exe |00241C13|Vcl.Controls
|TControl |Click |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|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible
gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76816DE8|user32.dll |00016DE8|USER32 |
| (possible GetThreadDesktop+389) | | |00000002|03
|00000000|76816E49|user32.dll |00016E49|USER32 |
| (possible GetThreadDesktop+486) | | |00000002|03
|00000000|77420107|ntdll.dll |00010107|ntdll |
|KiUserCallbackDispatcher | | |00000002|03
|00000000|768196D0|user32.dll |000196D0|USER32 |
|SendMessageW | | |00000002|03
|00000000|71AB459B|comctl32.dll |000A459B|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB45FE|comctl32.dll |000A45FE|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB4488|comctl32.dll |000A4488|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|768162F7|user32.dll |000162F7|USER32 |
| (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76820D32|user32.dll |00020D32|USER32 |
| (possible GetClientRect+192) | | |00000002|03
|00000000|76820D56|user32.dll |00020D56|USER32 |
|CallWindowProcW | | |00000002|04
|00000000|00646282|myapp.exe |00246282|Vcl.Controls |TWinControl
|DefaultHandler |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|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible
gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|768177CE|user32.dll |000177CE|USER32 |
| (possible CharPrevW+314) | | |00000002|03
|00000000|76817893|user32.dll |00017893|USER32 |
|DispatchMessageW | |
抱歉不清楚,我不知道如何在 Whosebug 编辑器中保持标签。
Copy(pfff,1,100)
很奇怪。您可以直接使用 pfff
并让编译器自动将指向空终止字符数组的指针转换为字符串。
FireDacConnection.ConnectionName := pfff;
在调用 Show
之前这样做肯定是有意义的。显示一个无模式的窗体,然后设置连接名称,然后释放窗体,这看起来确实很奇怪。事实上,即使在 DLL 中显示表单看起来也很奇怪。
也就是说,这不是导致您出现问题的原因。代码泄漏的唯一解释是调用约定不匹配,或者调用站点出现错误。传个PChar
,照着抄,不会走漏风声。
实现中的调用约定似乎是 register
。 DLL 中的声明应该是:
procedure LookPchar(pfff:Pchar); stdcall;
或者你没有在DLL代码中显示stdcall
?
您可能在调用站点时出错了。也许泄漏就在那里。我们看不到该代码。
查看您的各种编辑,FastMM 报告的泄漏不是由问题中的任何代码产生的。在解决问题之前,您需要隔离问题。那是你的下一步。
使用PChar
输入即可。在另一个方向上,从被调用者到调用者,有很多选择,但你没有在这里询问过。关于该主题有很多问题。
所以让我们来看看 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"; Total size=18; Count=1 |
为什么 Unicode 字符串的引用计数为 -1?如何预防?如何正确传递Unicode字符串?
我尝试了什么: 将其作为常量传递。 复制它(如示例和 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"; Total size=18; Count=1 | |-----------------------------------------------------------------------------------------------------------------------------------------| |00000002|04 |00000000|01D79D9C|outDll.dll|00009D9C|System
| |_NewUnicodeString |23897[6] | |00000002|04 |00000000|008A11BC|myapp.exe |004A11BC|Caller
|TForm2 |Button4Click |66[2] | |00000002|04 |00000000|00641C13|myapp.exe |00241C13|Vcl.Controls |TControl |Click |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|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76816DE8|user32.dll |00016DE8|USER32 |
| (possible GetThreadDesktop+389) | | |00000002|03
|00000000|76816E49|user32.dll |00016E49|USER32 |
| (possible GetThreadDesktop+486) | | |00000002|03
|00000000|77420107|ntdll.dll |00010107|ntdll |
|KiUserCallbackDispatcher | | |00000002|03
|00000000|768196D0|user32.dll |000196D0|USER32 |
|SendMessageW | | |00000002|03
|00000000|71AB459B|comctl32.dll |000A459B|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB45FE|comctl32.dll |000A45FE|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB4488|comctl32.dll |000A4488|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|768162F7|user32.dll |000162F7|USER32 |
| (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76820D32|user32.dll |00020D32|USER32 |
| (possible GetClientRect+192) | | |00000002|03
|00000000|76820D56|user32.dll |00020D56|USER32 |
|CallWindowProcW | | |00000002|04
|00000000|00646282|myapp.exe |00246282|Vcl.Controls |TWinControl
|DefaultHandler |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|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|768177CE|user32.dll |000177CE|USER32 |
| (possible CharPrevW+314) | | |00000002|03
|00000000|76817893|user32.dll |00017893|USER32 ||DispatchMessageW | |
抱歉不清楚,我不知道如何在 Whosebug 编辑器中保持标签。
Copy(pfff,1,100)
很奇怪。您可以直接使用 pfff
并让编译器自动将指向空终止字符数组的指针转换为字符串。
FireDacConnection.ConnectionName := pfff;
在调用 Show
之前这样做肯定是有意义的。显示一个无模式的窗体,然后设置连接名称,然后释放窗体,这看起来确实很奇怪。事实上,即使在 DLL 中显示表单看起来也很奇怪。
也就是说,这不是导致您出现问题的原因。代码泄漏的唯一解释是调用约定不匹配,或者调用站点出现错误。传个PChar
,照着抄,不会走漏风声。
实现中的调用约定似乎是 register
。 DLL 中的声明应该是:
procedure LookPchar(pfff:Pchar); stdcall;
或者你没有在DLL代码中显示stdcall
?
您可能在调用站点时出错了。也许泄漏就在那里。我们看不到该代码。
查看您的各种编辑,FastMM 报告的泄漏不是由问题中的任何代码产生的。在解决问题之前,您需要隔离问题。那是你的下一步。
使用PChar
输入即可。在另一个方向上,从被调用者到调用者,有很多选择,但你没有在这里询问过。关于该主题有很多问题。