互操作 C++ 时释放分配的内存
Posted
技术标签:
【中文标题】互操作 C++ 时释放分配的内存【英文标题】:free allocated memory when interoping c++ 【发布时间】:2015-10-26 05:58:32 【问题描述】:填充一个包含字符串的 stuct 数组,我测试了一个发现,在 c# 中它通过指针执行得更快:
struct name
int intv;
IntPtr strv;
当通过GetPacksPtr()
实现时:(参见下面的代码/签名)
这就是我编码的方式,但不确定我是否做得对......
说 ArrL=10,000
DataPack* DataPackArr;
List<DataPack> DataPackLst = new List<DataPack>(ArrL);
GetPacksPtr(ArrL, &DataPackArr);
DataPack* CurrentPack = DataPackArr;
for (int i = 0; i < ArrL; i++, CurrentPack++)
DataPackLst.Add(new DataPack() strv = CurrentPack->strv, intv = CurrentPack->intv );
我在哪里可以释放分配的内存,如
__stdcall
定义非托管代码必须释放内存,但谁是“按合同”的所有者......这令人困惑,我试图负责释放分配以最小的性能损失。
c++
extern "C" __declspec(dllexport) void __stdcall GetPacksPtr(int size, DataPack** DpArrPtr )
*DpArrPtr = (DataPack*)CoTaskMemAlloc( size * sizeof( DataPack ));
DataPack CurPackPtr = *DpArrPtr;
char aStr[]= "abcdefgHi";
for ( int i = 0; i < size; i++,CurPackPtr++ )
CurPackPtr->IntVal=i;
CurPackPtr->buffer = (char*)malloc(sizeof(aStr));
strcpy(CurPackPtr->buffer, aStr);
c#
[DllImport("exported.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
public static extern void GetPacksPtr(int RaySize, DataPack** DataPackArr);
【问题讨论】:
如果这只是 c++,你为什么要标记c?你为什么extern "C"
?你明白你在做什么吗?
@iharob 请参阅将字符串从 C++ API 返回到 C# =>limbioliong.wordpress.com/2011/06/16/…
我不是那个意思,我的意思是 c 不是 c++,你在混合东西。
@iharob 看看这个链接上的例子请...我也在学习....
【参考方案1】:
是的,这在您手动分配内存时很常见,当然速度更快,您需要另一个(这部分我不知道该说什么,因为您混合了所有内容)c 这样的函数
__declspec(dllexport) void __stdcall FreePacksPtr(int size, DataPack *DpArrPtr)
for (size_t i = 0 ; i < size ; ++i)
free(DpArrPtr[i].buffer);
CoTaskMemFree(DpArrPtr);
然后在您的 C# 中,只要您不再需要指针,只需调用 FreePacksPtr()
。
注意:您需要 extern "C"
的事实意味着 C# 代码期望从 dll 加载确切的符号,看来您必须指示 microsoft 编译器编译 c 代码而不是 c++,我不是 100% 确定,但微软编译器混合了这些。
【讨论】:
我正在使用extern "C"
,因为那是我刚刚复制的演示,但我确实测试过,因为我也确实对此提出了质疑..但删除时:Unable to find an entry point named 'GetPacksPtr' in DLL 'G:\....
是的,这就是我要告诉你的。编译 c++ 程序时,符号会发生变化,因此它可以支持重载以及我不太熟悉的那种东西。也许您只需将源文件扩展名更改为.c
。
我想这是一个技巧,如果我是对的,编写 cpp,通过声明 extern C 它编译一个 cDll,这就是我获得性能提升的原因......我想知道......跨度>
关于内存管理的故事,总的来说,谢谢你的好答案和代码解决方案。
仍然在想它试图决定一个释放内存的策略,而不是因为你所说的“直到最后”执行它,但当你需要完成工作时也不这样做,就像在后台操作这样的死点而不影响性能,在程序空闲的地方。【参考方案2】:
当您分配非托管内存时,您必须释放它 - 但没有关于谁负责释放的规则。
在非托管世界中,为每个需要释放的资源拥有一个“所有者”是一种常见的策略,这种所有权就是释放对象的责任。
如果函数 A 分配一块内存,然后将指针传递给函数 B,则有两种选择:
A 仍然是所有者,完成后将释放内存,B 不必处理释放内存但也不能保存指针以供以后使用,因为它可以随时被 A 释放
所有权从A转移到B,现在B负责释放,B返回后A不能对指针做任何事情,因为它可以随时被B释放
李>请注意,函数原型中没有任何东西代表所有权,这一切都是由编写 A 的程序员和编写 B 的程序员之间达成的协议(通常称为“按合同”)
现在,为了让事情变得更复杂,您可以从中分配许多内存块(称为“堆”),当您释放时,您需要释放到用于分配的同一堆中。
有几个堆由 Windows 管理,.net Marshal 类具有释放内存的方法。
malloc 使用的堆不是其中之一,malloc 分配的内存必须通过在调用 malloc 的同一个 dll 中调用 free 来释放。
最后但并非最不重要的一点是,分配和释放内存是您在非托管代码中可以做的最慢的事情之一,如果您经常这样做,您会遇到内存碎片和引用位置等问题(这个答案是足够长的时间而不进入它们)
分配和释放策略对非托管代码的性能有很大影响 - 这不会对您的性能产生最小的影响。
【讨论】:
但是正如你所看到的,nir,@iharob 在他的代码中给出了一个解决方案(额外的调用,额外的 cpu 时间)虽然 only 而我结束了对我的使用它可以accure 在程序部分的末尾,并且与托管替代 List以上是关于互操作 C++ 时释放分配的内存的主要内容,如果未能解决你的问题,请参考以下文章
本机 C++ 程序在使用 C++/CLI 和 C# 互操作 DLL 启动时崩溃