【发布时间】:2021-09-05 02:38:30
【问题描述】:
这是我描述流程的示例代码
C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct CppStruct
{
public int n;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string data;
}
C++ 结构
struct CppData
{
int N;
char Data[16];
};
C# 将委托传递给 C++
public delegate void Get(ref int count, out IntPtr[] o); // I want to get an array of data
在 C++ 中
typedef void(__stdcall* GetPtr)(int* count, void** o); //fptr
GetPtrcall CSharp = the delegate passed from C#
// 使用这个callCSharp回调C#
void* ptr = nullptr;
int count = 0;
callCSharp(&count, &ptr);
现在是关键点, 进入C#委托时
private static void FromCpp(ref int count, out IntPtr[] o)
{
var d = new CppStruct();
d.n = 1;
d.data = "data";
CppStruct[] ds = new CppCsharMapping[3] { d, d, d }; // Intended to put three elements as an array.
count = 3; // Let C++ knows, there will be 3 elements back.
int size = Marshal.SizeOf(d);
IntPtr[] pntArr = new IntPtr[3];
pntArr[0] = Marshal.AllocHGlobal(size);
pntArr[1] = Marshal.AllocHGlobal(size);
pntArr[2] = Marshal.AllocHGlobal(size);
for (int i = 0; i < 3; i++)
{
Marshal.StructureToPtr(ds[i], pntArr[i], true);
}
o = pntArr; // !!!!!!!!!!!!!!!!!!!!!!!!!!!! this line cause leak.
gPntArr = pntArr; //I used a static variable gPntArr to save pntArr for free this memory block after the return.
return;
}
// 从 Cpp 触发的另一个方法中类似下面的内容。确保 Cpp 读回数据。
void Free()
{
foreach(var m in gPntArr)
{
Marshal.FreeHGlobal(m);
}
}
现在C#返回后,C++可以无任何错误地读回数据。
CppData** back = (CppData**)ptr;
for (int i = 0; i < count; i++, back++)
{
// Print out the value
(*back)->N
(*back)->Data
}
但是我发现通过调用while(true){callCSharp(&ptr); Free();},内存不断增加,然后我发现o = pntArr;是导致这种情况的行。
但我不知道如何正确释放内存。
我找不到实现目标的方法,Cpp 调用 C# 委托来取回一个数组(使用 void* 是因为我可能需要来自 C# 的不同类型的数据,这是我要求单一类型数组的示例),所以上面的示例是我正在尝试的,也许它是错误的,但它有效。
我可以知道为什么这条线会导致泄漏吗?或者任何我可以改进或使用其他方法的东西
【问题讨论】:
-
看起来
pntArr是每次调用FromCpp时新分配的内存,所以也许你应该将它控制在全局List<Intptr[] > gPntArrList或类似的范围内,以便在FromCpp()中执行gPntArrList .Add(pntArr),然后foreach(var gPntArr in gPntArrList ) foreach(var m in gPntArr) { Marshal.FreeHGlobal(m); }intFree()
标签: c# c++ interop marshalling