Jbob Johan
Jbob Johan

Reputation: 221

free allocated memory when interoping c++

populating an array of stuct containing string, i have tested an found out that in c# it performed faster via a pointer :

struct name{
    int intv;
    IntPtr strv;
}

when implementing via GetPacksPtr():(see code/signatures below) that's how i code and not sure i am doing it right...

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

where can i free the memory allocated, as __stdcall defines that the unmanaged code has to free the memory but who is the owner "by cotract"...it's confusing, i am trying to be responsible for freeing allocations with minimum performance hit.

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

Upvotes: 2

Views: 812

Answers (2)

Nir
Nir

Reputation: 29594

When you allocate unmanaged memory you have to free it - but there are no rules about who is responsible for freeing.

In the unmanaged world it's a common tactic to have an "owner" for each resource that needs freeing, this ownership is the responsibility for freeing the object.

If function A allocates a block of memory and then pass a pointer to function B there are two options:

  1. A remains the owner and will free the memory when done, B doesn't have to deal with freeing the memory but also can't save the pointer for later because it can get freed at any time by A

  2. The ownership is transferred from A to B, now B is responsible for freeing and A can't do anything with the pointer after B returns because it could be freed at any time by B

Note that there is nothing in the function prototype that represents ownership this is all by agreement between the programmer writing A and the programmer writing B (and is often referred to as "by contract")

Now, to make things more complicated there are many blocks of memory you can allocate from (called "heaps") and when you free you need to free into the same heap you used for allocating.

There are several heaps managed by Windows and the .net Marshal class have methods for freeing memory into them.

The heap used by malloc is not one of them, memory allocated by malloc must be freed by calling free in the same dll that called malloc.

And, last but not least, allocating and freeing memory is one of the slowest things you can do in unmanaged code and if you do that a lot you get into trouble with things like memory fragmentation and locality of reference (this answer is long enough without getting into them)

Allocating and freeing strategies have a huge impact on the performance of unmanaged code - this will not have minimal impact on your performance.

Upvotes: 2

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53006

Yes this is very common when you allocate memory manually and it's of course faster, you need another (this part I don't know what to say because you mixed everything) function like this

__declspec(dllexport) void __stdcall FreePacksPtr(int size, DataPack *DpArrPtr)
{
    for (size_t i = 0 ; i < size ; ++i)
        free(DpArrPtr[i].buffer);
    CoTaskMemFree(DpArrPtr);
}

And then in your C# just call FreePacksPtr() whenever you don't need the pointer anymore.

NOTE: The fact that you need extern "C" means that the C# code is expecting to load the exact symbols from the dll, it seems like you have to instruct the microsoft compiler to compile c code instead of c++, I am not 100% sure but the microsoft compiler mixes these.

Upvotes: 2

Related Questions