使用平台 Invoke (C#) 在非托管代码中分配和释放内存
我想在非托管代码 (C++) 中分配和释放内存,我们将它们称为托管代码 (C#) 中的函数。 我不确定下面的代码是否没有内存泄漏?
C# 代码:
[DllImport("SampleDLL.dll")]
public extern void getString([MarshalAs(UnmanagedType.LPStr)] out String strbuilder);
[DllImport("SampleDLL.dll")]
public extern void freeMemory([MarshalAs(UnmanagedType.LPStr)] out String strBuilder);
....
//call to unmanaged code
getString(out str);
Console.WriteLine(str);
freeMemory(out str);
C++ 代码:
extern void _cdecl getString(char **str)
{
*str = new char[20];
std::string temp = "Hello world";
strncpy(*str,temp.c_str(),temp.length()+1);
}
extern void _cdecl freeMemory(char **str)
{
if(*str)
delete []*str;
*str=NULL;
}
I want to allocate and deallocate memory in unmanaged code (C++) and we call them functions from managed code (C#).
Iam not sure whether the following code is fine without memory leaks or not?
C# code:
[DllImport("SampleDLL.dll")]
public extern void getString([MarshalAs(UnmanagedType.LPStr)] out String strbuilder);
[DllImport("SampleDLL.dll")]
public extern void freeMemory([MarshalAs(UnmanagedType.LPStr)] out String strBuilder);
....
//call to unmanaged code
getString(out str);
Console.WriteLine(str);
freeMemory(out str);
C++ code:
extern void _cdecl getString(char **str)
{
*str = new char[20];
std::string temp = "Hello world";
strncpy(*str,temp.c_str(),temp.length()+1);
}
extern void _cdecl freeMemory(char **str)
{
if(*str)
delete []*str;
*str=NULL;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,这行不通。 pinvoke 编组器将尝试使用 CoTaskMemFree() 释放字符串的内存。否则它不知道你有一个释放函数。这不会很好地工作,您没有使用 CoTaskMemAlloc 分配字符串。在 XP 中这将是无声内存泄漏,在 Vista 及更高版本中将是崩溃。
您必须阻止编组器尝试执行正确的工作:
这需要 C# 代码中的 Marshal.PtrToStringAnsi() 自行从返回的指针编组字符串。
No, this cannot work. The pinvoke marshaller is going to try to release the memory for the string with CoTaskMemFree(). It doesn't otherwise know that you have a release function. That's not going to work well, you didn't allocate the string with CoTaskMemAlloc. This is going to be a silent memory leak in XP, a crash in Vista and up.
You have to stop the marshaller from trying to do the right job:
Which then requires Marshal.PtrToStringAnsi() in your C# code to marshal the string yourself from the returned pointer.
我个人认为使用
BSTR
可以最轻松地完成此操作,从而避免导出释放器。C++
当然,如果您使用 Unicode 字符串,那就更容易了。
C#
在 C# 方面就是这样。您只需调用
getString()
,它就会返回一个 .netstring
,并且您不需要编组任何内容或调用释放器。Personally I think this is most easily done using a
BSTR
and thus avoiding the need to export a deallocator.C++
Of course, if you are working with Unicode strings its even easier.
C#
And on the C# side that's it. You just call
getString()
and it returns a .netstring
and you don't need to marshall anything or call a deallocator.