I have a hypothetical COM object with the following signature
void MemAlloc(ref double test, int membercount)
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.