Why do we support pinned objects?

Patrick Dussud and I were talking
recently about why the CLR supports pinned object… here are some thoughts from
that discussion…."urn:schemas-microsoft-com:office:office" />

In order to pass data buffers
between unmanaged and managed code, we need to fix the address of the buffer
while it is being accessed by unmanaged code. We could have provided a special
allocator for this purpose but that would have required the programmer to be
aware of the fact that a buffer can be passed to an unmanaged piece of code
right from the start. Instead we provided a pinning mechanism, where any managed
buffer can be temporarily pinned or made unmovable by the GC. This is done
implicitly by the manage-to-unmanaged layer (Pinvoke and COM) for arguments of
certain classes such as String. This can also be done by creating a GCHandle
passing the type GCHandleType.Pinned and the buffer as arguments; the
buffer will stay pinned until the GCHandle is freed

 

Performance model for
pinned objects

While pinning is a flexible model
that avoids data copies from managed buffer to unmanaged buffers, it does have
some consequences on the performance of the managed program. Since GC isn’t able
to move pinned objects, the GC heap can get fragmented; which means that the
amount of memory allocated to the GC heap can be more than the data being used
by the program. The GC will create some free blocks around the pinned objects
that get in the way of compaction and if there are more of them than
opportunities to reuse them, memory usage becomes higher than necessary. The GC
has special policies to fight excessive fragmentation, but it comes at the
expense of spending more time in the garbage collection on average. It is the
old space/time tradeoff. Can the programmer do something about it? Yes, because
old, stable objects don’t move very much because they are surrounded by other
old stable objects so they can be pinned without creating much fragmentation.
New objects, allocated amongst a slew of temporary objects are the worse if they
are pinned for long period of time (such as a socket IO buffer, which has a
usually long latency). They are in the middle of the most compacting area of
memory and they stand in the way. The solution is for the IO buffers for long
latency operations to be allocated from and returned to a pool of stable
buffers, instead of being created and collected. This can make a big difference
on server applications where a lot of requests are executed simultaneously and
most of them wait on a long latency IO call.