C#调用返回指针的C ++方法。解释内存管理

时间:2010-10-26 22:49:35

标签: c# c++ memory-management pinvoke intptr

有人可以解释下面“主要”中2 C#行的低级/内存管理视角究竟发生了什么?

C ++代码(非托管):

    #define DLLEXPORT extern "C" __declspec(dllexport)

    DLLEXPORT MyClass* MyClass_MyClass()
    {
        return new MyClass();
    }
    DLLEXPORT void MyClass_setName(MyClass* myClass, const char* name)
    { 
        myClass->setName(name);
    }

MyClass::MyClass()
{
    _name.clear();
}
void MyClass::setName(const char* name)
{
    _name.setCString(name, NAME_MAX_BYTES);
}

C#代码:

        [DllImport(@"lib.dll")]
        private static extern IntPtr MyClass_MyClass();
        [DllImport(@"lib.dll")]
        public static extern void MyClass_setName(
                    IntPtr myClass,
                    [System.Runtime.InteropServices.InAttribute()]
                    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
                    string name);

        public static void Main(string[] args)
        {
            var myClass = MyClass_MyClass();
            MyClass_setName(myClass , "Test Name");
        }

具体来说,我想知道.NET如何知道为“myClass”分配的空间?它必须在后台做某种“Marshal.AllocHGlobal(SIZE)”,对吗?如果需要更多空间会发生什么(我设置了一个名字?)?此外,是否有任何垃圾收集的风险和移动内存并弄乱我的“IntPtr myClass”?

2 个答案:

答案 0 :(得分:1)

.NET对MyClass类型一无所知,它只存储指向它的指针。指针的大小始终是已知且固定的 - 32位进程为4个字节,64位进程为8个字节。在这种特殊情况下,所有内存分配和管理都发生在非托管C ++代码中:

return new MyClass();

在这里:

myClass->setName(name);

由C ++ DLL决定如何分配/释放/管理内存,C#代码只会调用此DLL的导入函数。

不会对您的非托管对象执行垃圾回收,您需要提供额外的(非托管)方法来释放它以避免内存泄漏。

答案 1 :(得分:0)

如果不管理c ++代码,.net不会分配除IntPtr之外的任何内容。它由c ++代码分配。

这意味着将在该IntPtr上完成唯一的垃圾收集。由于它很小,垃圾收集器可能需要很长时间才能清理它。

这意味着即使您的C ++代码自身清理得很好,也可能需要很长时间才能进行清理。 C ++代码可能使用了大量的内存,但它对.net是不可见的,所以它不会优先考虑它来清理“更大”的.net对象。