互操作签名不正确导致内存泄漏

时间:2011-04-14 12:43:30

标签: .net c++ memory-leaks interop marshalling

通过interop生成的接口从c#使用的第三方com模块正在泄漏内存

第三方c ++方法签名是:

somemethod(....., long** param3, long** param4)

生成的互操作方法是:

somemethod(...., IntPtr param3, IntPtr param4)

最后2个参数由umanaged dll分配数组,并从c#Marshal.CoMemFree中释放(不记得确切的sig atm)

从C ++通过com接口使用相同的方法并以相同的方式释放不会产生泄漏

从命令行使用tlbimp会产生:

TlbImp : warning TI0000 : At least one of the arguments for
'Sometype.somemethod' cannot be marshaled by the runtime
marshaler. Such arguments will therefore be passed as a pointer and may
require unsafe code to manipulate.

我发现令人惊讶的是长期** params无法自动编组。

比.net更好地理解c ++(不包括Com黑魔法),但实现.net方......

访问和释放param3和param4中传回的内存的正确方法是什么。我怀疑他们应该'出IntPtr'?

2 个答案:

答案 0 :(得分:3)

此声明与COM Automation严重不兼容。数组需要作为SAFEARRAY传递,因此很清楚它们有多大以及如何管理它们的内存。传递长**将通常表示被调用者负责分配数组并返回指向数组的指针。究竟它应该分配的是什么问题,不清楚它是应该使用进程堆,COM堆还是可以使用CRT堆。

Tlbimp.exe抛出一个拟合,它不知道如何正确翻译参数类型。您必须使用ildasm.exe反编译互操作库,编辑IL以将参数转换为IntPtr或out int []并使用ilasm.exe再次编译它。对分配器唯一合理的猜测是Marshal.AllocCoTaskMem()。可能会工作,可能会严重泄漏。您需要组件供应商或作者的帮助,以避免猜测。

答案 1 :(得分:0)

找到'a'获得预期功能的方法,不确定解决方案的声音。以下工作没有泄漏

long* arr1 = null;
long* arr2 = null;

IntPtr parr1 = new IntPtr(&arr1);
IntPtr parr2 = new IntPtr(&arr2);

somemethod(....., parr1, parr2);

Marshal.CoTaskMemFree(new IntPtr(arr1));
Marshal.CoTaskMemFree(new IntPtr(arr2));

注意事项:

  1. 没有尝试访问数组,我实际上并不需要内容,但是我想这可能需要Marshall.Copy调用。

  2. 直观地说,呼叫应该是某种方式(.....,ref parr1,ref parr2);然而看起来IntPtr实际上更像是一个void指针,所以尽管它是通过值传递的,它的值是arr1的地址,所以被调用者能够分配到arr1,闻起来错误但是它有效,可能arr1或parr1应该被分配Marshal.CoTaskMemAlloc(?)

  3. 我之前在控制台应用程序中尝试了上述内容并且仍然泄露,但是在指定[STAThread]时(与未指定/ default相反),泄漏停止。公寓事物改变了代码的含义,因此微妙的臭味