vrrathod
vrrathod

Reputation: 1240

how Marshal.FreeHGlobal() works?

I have a C# based UI which uses C++ based DLL. My requirement was to pass a big chunk of memory from C# to DLL. DLL will write into this memory buffer and pass it back to C#. I have used IntPtr & global memory functions to do this. Everything works fine.

The question is, How to verify if the Marshal.FreeHGlobal() has cleaned the memory? I am using big chunk of memory, usually in terms of MBs. So I want to make sure that the memory is cleaned instantly.

Upvotes: 1

Views: 7607

Answers (2)

Mark Sowul
Mark Sowul

Reputation: 10610

You can probably also allocate the array in managed memory, and then create a GCHandle to allow it to be accessed from unmanaged memory.

For example, here I call PowerReadACValue; the Win32 API function takes in an LPBYTE buffer (which equates to BYTE*).

First I call it with a "null pointer" (IntPtr.Zero), so that it will tell me what size buffer I need (this gets output into bufferSize). Then I allocate the buffer, and pass in the pointer via GCHandle's AddrOfPinnedObject.

uint type;
uint bufferSize = 0;

if (SafeNativeMethods.PowerReadACValue(IntPtr.Zero, this.m_planHandle, ref subGroupOfPowerSettingsGuid, ref powerSettingGuid, out type, IntPtr.Zero, ref bufferSize) != 0)
{
    throw new Win32Exception();
}

byte[] buffer = new byte[bufferSize];
GCHandle bufferPointer = default(GCHandle);
try
{
    bufferPointer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    if (SafeNativeMethods.PowerReadACValue(IntPtr.Zero, this.m_planHandle, ref subGroupOfPowerSettingsGuid, ref powerSettingGuid, out type, bufferPointer.AddrOfPinnedObject(), ref bufferSize) != 0)
        throw new Win32Exception();
}
finally
{
    if (bufferPointer.IsAllocated)
        bufferPointer.Free();
}

Alternatively, I could have allocated the buffer with Marshal.AllocHGlobal, which also returns me an IntPtr, and then afterwards free it with Marshal.FreeGlobal, but in this case I need to use the data in the array from managed code. If I were simply going to pass the array pointer to another unmanaged function without ever touching it from managed code, this would be a better way to go (while the GCHandle is active, the memory is locked into place in memory which affects the garbage collector).

Upvotes: 0

Jim Mischel
Jim Mischel

Reputation: 134125

If you pass a valid handle to Marshal.FreeHGlobal, it will be freed. But since the method doesn't return a value, you can't say for sure whether it was cleaned up.

If you have some doubt as to whether you're passing the right thing to FreeHGlobal, then I suggest that your code probably isn't as clean as it should be. But if you really want to make sure, then you could call the LocalFree Windows API function, passing it the handle that you would have passed to FreeHGlobal:

[DllImport("kernel32", SetLastError=true)]
static extern IntPtr LocalFree(IntPtr mem);

// Now, to free a block of memory allocated with Marshal.AllocHGlobal
IntPtr rslt = LocalFree(memPtr);
if (rslt == IntPtr.Zero)
{
    // success!
}
else
{
    int err = Marshal.GetLastWin32Error();
    // do something with the error.
}

I would suggest, however, that if you do this, that you call LocalAlloc to allocate the memory rather than calling Marshal.AllocHGlobal, as it's possible (although probably unlikely) that future versions of .NET could use something other than LocalAlloc to allocate unmanaged memory. If that happened, then your code that depends on LocalFree would break.

Upvotes: 5

Related Questions