Reputation: 1240
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
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
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