在使用c ++时可以自由分配内存

时间:2015-10-26 05:58:32

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

填充包含字符串的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定义了非托管代码必须释放内存,但谁是“通过cotract”的所有者...这令人困惑,我正在尝试负责释放分配以最低性能命中

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);

2 个答案:

答案 0 :(得分:2)

是的,当你手动分配内存时这是很常见的,它当然更快,你需要另一个(这部分我不知道该说些什么,因为你混合了一切)这样的功能

var errorsHtml = '<div class="alert alert-danger"><ul>';
errorsHtml += '<li>' + errors.errors.join('</li><li>') + '</li>';
errorsHtml += '</ul></div>';

然后在你的C#中,只要你不再需要指针就调用__declspec(dllexport) void __stdcall FreePacksPtr(int size, DataPack *DpArrPtr) { for (size_t i = 0 ; i < size ; ++i) free(DpArrPtr[i].buffer); CoTaskMemFree(DpArrPtr); }

注意:您需要FreePacksPtr()的事实意味着C#代码期望从dll加载确切的符号,似乎您必须指示Microsoft编译器进行编译c代码而不是c ++,我不是100%肯定,但微软编译器混合了这些。

答案 1 :(得分:2)

当您分配非托管内存时,您必须释放它 - 但是没有关于谁负责释放的规则。

在非管理的世界中,为每个需要释放的资源拥有“所有者”是一种常见的策略,这种所有权是释放对象的责任。

如果函数A分配一块内存然后将指针传递给函数B,则有两个选项:

  1. A仍然是所有者并且在完成后将释放内存,B不必处理释放内存但也无法保存指针以供以后使用,因为它可以随时被A <释放/ p>

  2. 所有权从A转移到B,现在B负责释放,A在B返回后无法对指针做任何事情,因为它可以随时被B释放

  3. 请注意,函数原型中没有任何内容代表所有权,这完全是由编写A的程序员和编写B的程序员之间的协议(通常称为“按合同”)

    现在,为了使事情变得更复杂,可以分配许多内存块(称为“堆”),当你释放时,你需要释放到用于分配的同一堆中。

    有几个由Windows管理的堆,而.net Marshal类有释放内存的方法。

    malloc使用的堆不是其中之一,malloc分配的内存必须通过在调用malloc的同一个dll中调用free来释放。

    而且,最后但并非最不重要的一点是,分配和释放内存是你可以在非托管代码中做的最慢的事情之一,如果你做了很多,你会遇到内存碎片和引用位置等问题(这个答案是足够长,没有进入他们)

    分配和释放策略会对非托管代码的性能产生巨大影响 - 这对您的性能影响不大。