Marshal.FreeHGlobal()如何运作?

我有一个基于C#的UI,它使用基于C ++的DLL。 我的要求是将大量内存从C#传递给DLL。 DLL将写入此内存缓冲区并将其传递回C#。 我使用IntPtr和全局内存函数来做到这一点。 一切正常。

问题是,如何validationMarshal.FreeHGlobal()是否清理了内存? 我正在使用大块内存,通常以MB为单位。 所以我想确保立即清理内存。

如果将有效句柄传递给Marshal.FreeHGlobal ,它将被释放。 但由于该方法不返回值,因此无法确定是否已清除该值。

如果你对是否将正确的东西传递给FreeHGlobal ,那么我建议你的代码可能不是那么干净。 但是如果你真的想确定,那么你可以调用LocalFree Windows API函数,传递你传递给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. } 

但是,我建议,如果你这样做,你调用LocalAlloc来分配内存而不是调用Marshal.AllocHGlobal ,因为可能(虽然可能不太可能).NET的未来版本可以使用除LocalAlloc以外的东西来分配不受管理的内容记忆。 如果发生这种情况,那么依赖于LocalFree代码就会中断。

您也可以在托管内存中分配数组,然后创建GCHandle以允许从非托管内存访问它。

例如,我在这里调用PowerReadACValue ; Win32 API函数接收LPBYTE缓冲区(相当于BYTE* )。

首先我用“空指针”(IntPtr.Zero)调用它,这样它就会告诉我需要什么大小的缓冲区(这会输出到bufferSize)。 然后我分配缓冲区,并通过GCHandleAddrOfPinnedObject传入指针。

 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(); } 

或者,我可以用Marshal.AllocHGlobal分配缓冲区,它也返回一个IntPtr ,然后用Marshal.FreeGlobal释放它,但在这种情况下我需要使用托管代码中的数据。 如果我只是将数组指针传递给另一个非托管函数而不从托管代码触及它,这将是一个更好的方法(当GCHandle处于活动状态时,内存被锁定在内存中,这会影响垃圾收集器)。