.NET Memory Management and GCHandle
GC Handle provides facilities to explicitly control and monitor the lifetime of an object in heap.Whenever an appdomain loads it creates a GC Handle table which maintains a list of pointers and corresponding GC Handle type.The GC Handle can be obtained using the structure System.Runtime.InteropServices.GCHandle and System.Runtime.InteropServices.GCHandleType enumeration.The GCHandleType can have the following values:
- This type of GC Handle allow the object to be collected.When the object is collected the GCHandle is zeroed even if the finalizer resurrect the reference.
- This is similar to Weak apart from the fact that it is not zeroed if the object is resurrected during finalization.
- This GC Handle prevents the object from being collected.
- This GC Handle prevents the object from being collected as well moved during heap compaction.
The GCHandle is obtained using the GCHandle.Alloc method and it is freed using the GCHandle.Free() method as shown in the code sample below:
byte buffer = new byte;
GCHandle hnd = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr ptr = hnd.AddrOfPinnedObject();
//Call unmanged code.....
if (hnd.IsAllocated) hnd.Free();
If you are using a Normal GCHandle then AddrOfPinnedObject cannot be used.The pointer can be obtained using
The GCHandleType Pinned is particularly used for passing reference between managed and unmanaged code during the P/Invoke calls.But pinning has impact on the performance of the garbage collector.So it is very important to have a clear idea on when to pin the object.In most of the CLR P/Invoke layer automatically pins an object before the call and unpins it after the call returns.This is much more efficient than explicit pinning using GCHandle.But there can be situation when we need to keep the object fixed in memory even after the unmanaged function returns.This is very much true in case of an asynchronous unmanaged call involving I/O operation.For example if I am making an unmanaged function which takes a file handle and buffer as input and asynchronously reads the file and populates the buffer then it is absolutely necessary to keep the buffer fixed in memory.
This is explained in Chris Brummes Blog very crisply.
The PnP Interop Performance Guidelines also clearly suggests to Avoid Aggressive Pinning of Short-Lived Objects