Selected posts on CLR, threading, Internationalization and WPF
My quest to select a good Antivirus for the year 2008

Memory control : Use GCHandle to pin down the objects

In the .NET framework memory control is mostly autonomous and is controlled by the CLR. Although in managed languages we do not care much about controlling memory but when we have to interact with other languages we have to be aware of the memory implications. When we create an object in memory there is no guarantee that the object will remain in the same location it was created in. This is because the GC moves memory around by itself when needed to.

Variable movement in memory

I am sure that everyone reading this have already read about how GC collects memory and generations. As you know that GC allocates memory spaces in bulk. When needed GC collects unused memory and moves it. For example if the object you are using is collected, in order make better allocation GC can move it a different block of memory and free the block you were in. Let think we have a variable called "x" and it allocated in the memory like in the position like shown below.

 GC Generation

Figure 1: Before GC collection

in the figure above 1 is the space that are allocated and 0 are the ones that need to garbage collected because there is no reference to it. When GC collects it might decide to move the occupied items to the top block keep the second block empty by compacting. If so our memory could look like this diagram below

GC Generation1 
Figure 2: After compacting the variable moved to different virtual address

As you see that GC has moved all items to the first block of memory and the second block is empty which will result in faster memory allocation for new variables and it makes sense to do to so. Our variable x has moved to a different location in memory space which means the address of the memory where the variable is kept has changed. (Please keep in mind that the address space used does not have anything is physical ram as the OS may decide to change the physical address anytime and the address we are referring to is virtual address. Usually GC collect after 256KB of memory has become occupied, depending on the version of GC and OS and the mode it runs. As GC is independent of the thread you are running, it can collect any time.

GC Thread

If you are doing unmanaged memory operation and you are using the memory address and GC can come in move the memory away as you use the address to do unmanaged operations.

Pin down: API Calls to PInvoke

So can can this be a problem when we are calling windows APIs? For example, what happens if the window handle (hwnd) that I specified in the pinvoke is moved to a different memory address. The variable is pinned down to memory before the PInvoke call and pinned status is released just after the call. This is done automatically by the CLR. So what would have happened if GC had come in while the unmanaged PInvoke was running? See the figure below

GC Generation 3

As you can see in the figure above that the variable x  did not move to another virtual address in memory. This is useful when I need some unmanaged code to access a memory address that is constant. For example lets think of a scenario where I have an integer array which I pass to some unmanaged function and then I change the values of the variable at times and unmanaged function read changed values in the integer array and does some work. In such a scenario I will need the array to remain in one constant space. So I will need GCHandle class to pin it down in memory

GCHandle class

We find the class in System.Runtime.InteropServices namespace. In order use this class we will need SecurityPermission with Unmanaged code flag most of the time. Each application domain has a for GC handles, with this GCHandle class we can control what items are in that table. The Garbage Collector actually reads this table  and abides by it. Each entry in the table points to an object in the managed heap and how GC should treat it. There are four behaviors types as described in the GCHandleType enumeration. They are as follows,
    1. Weak
    2. WeakTrackResurrection
    3. Normal
    4. Pinned

Weak and WeakTrackResurrection for tracking weak referenced objects (see earlier post WeakReference: GC knows the Best for more on weak references). The Normal type is used to keep an object alive even if there are no reference to it. We are interested in the last type called Pinned. This tells the Garbage Collector to keep this object in memory even if there are no reference to it and never to move this object around in memory. See an example below on how to use the GCHandle class

string name = "My Name";
byte[] nameinbyte = ASCIIEncoding.ASCII.GetBytes(name);
// Pin down the byte array
GCHandle handle = GCHandle.Alloc(nameinbyte, GCHandleType.Pinned); 
IntPtr address = handle.AddrOfPinnedObject ();
// Do stuff ... with the pinned object address 
// ....

Things to Remember

Please note that too many pinned object will make the GC slowdown. Also only blittable types and arrays of blittable types can be used. If you have written a custom object you can make it blittable by implenting a custom marshaler with the ICustomMarshaler interface.

kick it on


Leon Anderson

Hey there, great topic! I am trying to create a poor mans singleton class where I can use the New() to pass reference to the shared object. I am trying to do this with this bit of code, however it isn't quite working how I had hoped...maybe you can guide me, seeing as you are quite advanced with this topic.

Any help would be greatly appreciated!
Private Shared oSession As Session = Nothing
Public Sub New(ByVal viSessionId As Integer)
If oSession Is Nothing OrElse (oSession.SessionId <> viSessionId) Then
SessionId = viSessionId
miCieId = SYSessio.cie_id
miSuccId = SYSessio.succ_id
miDeptId = SYSessio.dept_id
miUserId = SYSessio.cle_user
If oSession Is Nothing Then
oSession = Me
End If
Dim gh As System.Runtime.InteropServices.GCHandle
gh = System.Runtime.InteropServices.GCHandle.Alloc(Me)
gh.Target = oSession -> problem here!
'oSession is ok, but gh.Target not pointing to oSession after here.
End If
End Sub

Public Shared Function GetCurrentSessionObject() As Session
If oSession Is Nothing Then
oSession = New Session(CInt(System.Threading.Thread.CurrentPrincipal.Identity.Name))
End If
Return oSession
End Function

Shafqat Ahmed

A few comments first. The session does not look like an HttpSession, let me assume that it is a custom session object. Please explain what you are trying to achive by converting "Thread.CurrentPrincipal.Identity.Name"
to an integer which should fail at times and which can even be empty at times.

If you want to identify a thread with integer then use "AppDomain.GetCurrentThreadId()"
to get the running thread's numeric id.

If you want the username under which the code is running then use
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
string username = "" + wp.Identity.Name;

Also please elaborate the benefit you are expecting by creating a GC handle and then freeing it in the same method when the object that is being set is not null.

When we do an alloc, it means that the GCHandleType is normal which infact will not let the object be garbage collected even if the object does not have any reference. Also when you are doing "System.Runtime.InteropServices.GCHandle.Alloc(Me)"
then why do this "gh.Target = oSession"? You could just call System.Runtime.InteropServices.GCHandle.Alloc(oSession) directly.

Please elaborate a little more about the objective because I am unable understand the reason for using GCHandle

Leon Anderson

Thank you for your time and effort already, I have no problem with the
Thread.CurrentPrincipal.Identity.Name which you mention of, the question is more about using
the pointer reference to object.

I use the GCHandle to make a handle on the newly created Me inside the New() statement, then assign an already created variable (the singleton with the same ID) this is a way (i think) of trying to limit the resources used, by creating a single copy of an object (unless diff. ID selected as per my code) This way it means that I have a singleton object but without using the usual GetInstance() method, I was trying to do this on the New call of my object class.

Someone mentioned trying to use the IClonable , but that method wont work, as I would not be able to assign anything to Me inside the New method using Me = oSession.Clone, else I would have just done Me = oSession.(this gives error)
This is the reason for using the gchandle , as I am assigning the reference of my first object to my newly created object(using its handle).....sounding more like c++, but I figured it might be the only way to get my singleton implementation of an object already being used by many people without breaking their code.

Leon Anderson

Is there anything you could think of about my last comment that would make it possible to do what I need to accomplish, think of it if you will as using C like pointers to point to an object at the time of creation. If the New has a different Id as a parameter, you create a new instance of that class, but if the Id is the same, you pass the one already being help in a static variable to the pointer of the New statement (the Me)

The comments to this entry are closed.