Steve
Steve

Reputation: 12004

Does C# clean up C++ allocated memory?

I have a hypothetical COM object with the following signature

void MemAlloc(ref double[] test, int membercount)

where the memory is allocated in C++ using new/malloc. Once this is in C#, using the RCW, how do I ensure that the memory is freed correctly? I would think it would be difficult for .NET to free, considering in C++ you need to know if it was allocated with new/malloc/mm_malloc before you can correctly free it. So, what is the appopriate way to cleanup my C++ allocated array? Thanks.

Upvotes: 9

Views: 6393

Answers (4)

JaredPar
JaredPar

Reputation: 754833

I'm almost 100% sure the CLR will not automatically free the memory allocated for test (if it were P/Invoke I would be 100% sure). The reason being, how does the CLR know what you used to allocate the memory in the first place? Namely it doesn't.

A safer way to write this function is as follows

void MemAlloc(ref IntPtr arrayPtr, int membercount)

Once you get the call back you can do the following.

var count = GetTheCount();
var arrayPtr = IntPtr.Zero;
obj.MemAlloc(ref arrayPtr, count);
byte[] test = MarshalThePtrToByteArray(arrayPtr, count);
Marshal.FreeCoTaskMem(arrayPtr);

Here is a quick and dirty implementation of MarashalThePtrToByteArray

byte[] MarashalThePtrToByteArray(IntPtr ptr, int count) {
  byte[] arr = new byte[count];
  for ( int i = 0; i < count; i++ ) {
    arr[i] = (byte)Marshal.PtrToStructure(ptr, typeof(byte));
    ptr = new IntPtr(IntPtr.ToInt64() + Marshal.SizeOf(typeof(byte)));
  }
  return arr;
}

Upvotes: 1

Shea
Shea

Reputation: 11243

I believe you should use CoTaskMemAlloc() for memory that you want to explicitly free from the managed side. The CLR will take care of freeing the memory once it's no longer reachable. If you want to free it explicitly you can use the managed Marshal.CoTaskFree() routine.

In general the interop marshaler and CLR abide by COM conventions for freeing memory; the recipient is responsible for freeing memory. So the CLR/Interop marshaler will usually take care of freeing memory that was allocated in a native call if that memory is returned to the managed caller.

From Memory Management with the Interop Marshaler (msdn):

The interop marshaler always attempts to free memory allocated by unmanaged code. This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

The runtime always uses the CoTaskMemFree method to free memory. If the memory you are working with was not allocated with the CoTaskMemAlloc method, you must use an IntPtr and free the memory manually using the appropriate method.

Upvotes: 9

Sneal
Sneal

Reputation: 2586

The book .NET 2.0 Interoperbility Recipes looks to be handy. It seems to agree with what Arnshea said about CoTaskMemFree.

Upvotes: 1

plinth
plinth

Reputation: 49189

Wrap it in an object that implements IDisposable and make sure that the C# wrapper gets disposed.

Here's a blog I wrote about an easy way to implement IDisposable.

Upvotes: 6

Related Questions