s k
s k

Reputation: 5202

Delete memory allocated in C# in C++ code

I have codes interop between C# (core) and C++ (unmanaged DLL).

Memory allocated in C# using Marshal.AllocHGlobal() needs to be released in C# using Marshal.FreeHGlobal().

Memory allocated in C++ using new needs to be released in C++ using delete.

Can I just delete or FreeHGlobal() whenever I wish, since the GC is no longer tracing these memory handler?

Upvotes: 0

Views: 1137

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596497

No, you cannot just use whatever method you want to free memory. You MUST use whatever the allocator requires you to use. Only the memory manager that allocates a given block of memory knows how to free that block of memory properly.

For instance, the documentation for Marshal.AllocHGlobal() states:

This method exposes the Win32 LocalAlloc function from Kernel32.dll.

When AllocHGlobal calls LocalAlloc, it passes a LMEM_FIXED flag, which causes the allocated memory to be locked in place. Also, the allocated memory is not zero-filled.

And the documentation for LocalAlloc() states:

To free the memory, use the LocalFree function. It is not safe to free memory allocated with LocalAlloc using GlobalFree.

Which is what Marshal.FreeHGlobal() uses:

FreeHGlobal exposes the LocalFree function from Kernel32.DLL, which frees all bytes so that you can no longer use the memory pointed to by hglobal.

So, it is allowed for C# code to allocate memory using Marshal.AllocHGlobal() and then for C++ code to free that memory using LocalFree(). And conversely, for C++ code to allocate memory using LocalAlloc(LMEM_FIXED) and then for C# code to free that memory using Marshal.FreeHGlobal().

Likewise, the Marshal class also has a Marshal.AllocCoTaskMem() method:

This method exposes the COM CoTaskMemAlloc function, which is referred to as the COM task memory allocator.

Memory allocated by CoTaskMemAlloc() is freed with CoTaskMemFree():

Frees a block of task memory previously allocated through a call to the CoTaskMemAlloc or CoTaskMemRealloc function.

Which is what Marshal.FreeCoTaskMem() uses :

FreeCoTaskMem exposes the COM CoTaskMemFree function, which frees all bytes so that you can no longer use the memory that the ptr parameter points to.

So, it is allowed for C# code to allocate memory using Marshal.AllocCoTaskMem() and then for C++ code to free that memory using CoTaskMemFree(). And conversely, for C++ code to allocate memory using CoTaskMemAlloc() and then for C# code to free that memory using Marshal.FreeCoTaskMem().

Now, that being said, the memory manager that C++ uses for its new and delete operators is implementation-defined. There is no guarantee (or likelihood) that new uses LocalAlloc() or CoTaskMemAlloc(), or that delete uses LocalFree() or CoTaskMemFree().

So, it is not legal for C# to free any memory allocated with new, or for C++ to delete any memory allocated by C#.

Upvotes: 5

Related Questions