POP QUIZ: Why should we pin a managed object?
Please leave your answer as a comment. I will approve all comments by the following day and give the answer sometime tomorrow or Friday.
And for extra credit: Why we should unpin an object as quickly as we can?
Comments
Anonymous
February 20, 2008
You've been kicked (a good thing) - Trackback from DotNetKicks.comAnonymous
February 20, 2008
Managed objects should be pinned whenever pointers to them or into them are passed to unmanaged or unsafe code. By pinning the object, it guarantees the garbage collector won't move the object, ensuring the unmanaged pointer remains valid. Within verifiable managed code, pinning is not necessary because, even if a GC run occurs and moves the underlying object in memory, all references to the object held within the managed code are automatically updated in a way that's transparent to the programmer. Objects should be unpinned as soon as possible because pinned objects can cause fragmentation in the managed heap. This has several negative effects: it can reduce the amount of usable available heap space by limiting the contiguous size available for an allocation (which may even lead to an out-of-memory condition when it appears there's more than enough space available in the heap); it can affect how well the garbage collector can compact the heap, causing poorer cache locality; and it can slow down additional memory allocations, since in the absence of a pinned object fragmenting the heap, allocations in .NET can be as simple as bumping a heap pointer forward, but with a pinned object in the way, the process of working around the pinned block becomes more complex and time-consuming.Anonymous
February 20, 2008
I'll bite - You pin objects in order to use them in interop scenarios. For the extra credit, you unpin as quickly as possible in order to minimize memory defragmentation. Do I win a Zune? :)Anonymous
February 20, 2008
A managaed object should be pinned if you are passing the object to unmanaged code. You should unpin an object as quickly as possible to allow the garbage collector compact to occur.Anonymous
February 20, 2008
The comment has been removedAnonymous
February 20, 2008
Pin it to access it from unmanaged code. Unpin as fast as possible to limit time the GC is hampered.Anonymous
February 21, 2008
I'll comment on the extra credit, with a contrary viewpoint. There are times, actually, when you don't want to un-pin managed objects. Doing so can actually be detrimental to application performance. Take the case where you're writing a large socket server. For this, you need to have lots and lots of buffers avilable (4k or so in size) to hand over to "Socket.BeginRead". The answer to a problem like this, is that if you don't do any pinning, you'll end up with managed objects pinned all over your heap for non-deterministic lengths of time. Instead, allocate a large chunk of these buffers at once. This is typically done at app startup, so all the allocates happen in a single heap segment, near the bottom of the heap. Some algorithms advocate allocating a large object, out of the LOH, and using ArraySegment<T> to split it up. As these objects are allocated, they need to be immediately pinned. They will remain pinned for the lifetime of the application. If your pool of buffers is exhausted, then run GC to compact the heap as much as possible, and allocate another big chunk of buffers. Doing this keeps the pinned memory together, preferably in the same segment (which in turn gets promoted into Gen2), and minimizes fragmentation. Without doing this, the buffers get allocated all over the heap, and pinned for some amount of time. When the async operation completes they're unpinned. In an app like a socket server, a call to socket.BeginRead may take 10 minutes to return, if the socket on the other end isn't sending any data. Likewise, calls to socket.BeginWrite may take a while to return depending on a wide array of factors.Anonymous
February 21, 2008
Chris, This is a very good point and can be a very tricky situation to deal with. That is a good way to handle it. Another way to handle this type of situation which gets around having to keep things pinned all the time would be to allocate an array of buffers and pin/unpin them as needed, but keep the array around (static) so that it will always stay in the same segment. This way you don't have to keep things pinned and this segment can still be collected normally when objects aren't in use.Anonymous
February 21, 2008
The problem is that, in a server, the objects are typically "always" in use. They're cycled between one socket and other, but basically anytime you need to do something (BeginRead, BeginWrite, etc) you check a buffer out of the pool. ... when the async operation completes, you check your buffer back into the pool. In a steady state way, this means you continually re-use the pinned objects. For something like a server application, a reasonable expectation is that the segment will never be collected - at least not until the process is ready to shutdown.Anonymous
September 18, 2008
Great post, really helped me understand, thanks!