固定对象
GC (垃圾收集器)负责清理我们的垃圾。
当 GC 清理我们的垃圾时,他会从托管堆中删除未使用的对象,这会导致堆碎片。当 GC 完成删除时,它会执行堆压缩(defragmintation),这涉及在堆上移动对象。
由于 GC 不是确定性的,当将托管对象引用/指针传递给本机代码时, GC 可以随时启动,如果它恰好在 Inerop 调用之后发生,那么对象(传递给本机的引用)很可能会在托管堆上移动 - 结果,我们在托管端获得了无效的引用。
在这种情况下,你应该在将对象传递给本机代码之前固定该对象。
固定对象
固定对象是 GC 不允许移动的对象。
Gc 固定手柄
你可以使用 Gc.Alloc 方法创建一个 pin 对象
GCHandle handle = GCHandle.Alloc(yourObject, GCHandleType.Pinned);
- 获取固定 GCHandle 到托管对象会将特定对象标记为 GC 无法移动的对象,直到释放句柄为止
例:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void EnterCriticalSection(IntPtr ptr);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void LeaveCriticalSection(IntPtr ptr);
public void EnterCriticalSection(CRITICAL_SECTION section)
{
try
{
GCHandle handle = GCHandle.Alloc(section, GCHandleType.Pinned);
EnterCriticalSection(handle.AddrOfPinnedObject());
//Do Some Critical Work
LeaveCriticalSection(handle.AddrOfPinnedObject());
}
finaly
{
handle.Free()
}
}
注意事项
- 当固定(特别是大的)对象尝试尽可能快地释放固定的 GcHandle 时,因为它会中断堆碎片整理。
- 如果你忘记释放 GcHandle 什么都不会。在安全的代码部分(例如最终)进行