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