5

I pin an object on .NET and get a GCHandle. I want to leak most of these GCHandle and forget about them (so the objects continue to be pinned). Later, for a few objects I want to unpin them. At that point I only have the object (or the address of the object).

It seems each GCHandle pinning call returns a fresh GCHandle. The GCHandle.ToIntPtr and GCHandle.FromIntPtr show the native ints are equivalent to these GCHandles.

Is it possible to get the GCHandle(s) from an object or from the AddrOfPinnedObject?

James
  • 53
  • 3
  • I'm looking for the same solution. I have a third party component that is no longer supported and that appears to be pinning an object that we own. I want to force that object to be freed but do not have a reference to the GCHandle. If you find any solution please pass it along. – jpierson Nov 16 '11 at 18:33

2 Answers2

4

No, once you lose a GCHandle then you've lost it forever. There is no notion of a 'handle to a handle' in the garbage collector. You can only create a new GCHandle for an object, it will add an extra reference. The object this lost handle references will be permanently referenced, it is a leak. Note that GCHandle is a struct type.

The idea of keeping objects pinned for any length of time is detrimental to your program's perf. Short from giving the GC a harder time to work around the obstacles, it also prevents it from compacting the heap properly. This increases the likelihood of cache misses, very expensive on modern cores. These side effects can last for a while.

If you need pinned memory then allocate it with Marshal.AllocCoTaskMem(). This also stops you from creating pointers to managed data that has an unpredictable memory layout. Layout that differs between different versions of the JIT compiler and is highly dependent on the struct or class declaration. Only Marshal.StructureToPtr() can give you hard guarantees.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Marshal.AllocCoTaskMem looks relevant. Thanks. http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.alloccotaskmem.aspx – James Nov 10 '10 at 14:38
  • Marshal.AllocHGlobal is here http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.allochglobal.aspx – James Nov 10 '10 at 15:00
  • Hans has good advice here http://stackoverflow.com/questions/1887288/marshal-allochglobal-vs-marshal-alloccotaskmem-marshal-sizeof-vs-sizeof/1887765#1887765 – James Nov 10 '10 at 15:00
0

For those ones you need to free, keep GCHandles and use Free. GCHandle knows about the object and not the other way around.

Also it is not great that you want to keep the objects Pinned. I hope you realise you will be preventing GC to work correctly.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • It seems like we need to maintain the ptr to GCHandle table to support unpin in response to a "free" on the ptr. – James Nov 10 '10 at 14:06
  • I realise pinning will fix objects in the heap. Is there a way to ensure they are in the large object heap? – James Nov 10 '10 at 14:07
  • Make them large; 128kb ought to do but google it. Why do you need to pin large amounts of objects anyway? – Anton Tykhyy Nov 10 '10 at 14:26
  • Google reports that the size is a tuned value, e.g. 85000 bytes. http://msdn.microsoft.com/en-us/magazine/cc534993.aspx AFAIK, the objects were buffers to be passed into some pre-existing unmanaged code. – James Nov 10 '10 at 14:40