固定物件

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 什麼都不會。在安全的程式碼部分(例如最終)進行