Foundations of Programming - Karl Seguin
Foundations of Programming - Karl Seguin
Foundations of Programming - Karl Seguin
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Chapter 7 - Back to Basics: Memory<br />
Pinning<br />
Pinning occurs when an object is locked to a specific address on the heap. Pinned memory cannot be<br />
compacted by the garbage collector resulting in fragmentation. Why do values get pinned? The most<br />
common cause is because your code is interacting with unmanaged code. When the .NET garbage<br />
collector compacts the heap, it updates all references in managed code, but it has no way to jump into<br />
unmanaged code and do the same. Therefore, before interoping it must first pin objects in memory.<br />
Since many methods within the .NET framework rely on unmanaged code, pinning can happen without<br />
you knowing about it (the scenario I'm most familiar with are the .NET Socket classes which rely on<br />
unmanaged implementations and pin buffers).<br />
A common way around this type <strong>of</strong> pinning is to declare large objects which don't cause as much<br />
fragmentation as many small ones (this is even more true considering large objects are placed in a<br />
special heap (called the Large Object Heap (LOH) which isn't compacted at all). For example, rather than<br />
creating hundreds <strong>of</strong> 4KB buffers, you can create 1 large buffer and assign chunks <strong>of</strong> it yourself. For an<br />
example as well as more information on pinning, I suggest you read Greg Young's advanced post on<br />
pinning and asynchronous sockets.<br />
There's a second reason why an object might be pinned - when you explicitly make it happen. In C# (not<br />
in VB.NET) if you compile your assembly with the unsafe option, you can pin an object via the fixed<br />
statement. While extensive pinning can cause memory pressures on the system, judicial use <strong>of</strong> the<br />
fixed statement can greatly improve performance. Why? Because a pinned object can be manipulated<br />
directly with pointer arithmetic - this isn't possible if the object isn't pinned because the garbage<br />
collector might reallocate your object somewhere else in memory.<br />
Take for example this efficient ASCII string to integer conversion which runs over 6 times faster than<br />
using int.Parse.<br />
public unsafe static int Parse(string stringToConvert)<br />
{<br />
int value = 0;<br />
int length = stringToConvert.Length;<br />
fixed(char* characters = stringToConvert)<br />
{<br />
for (int i = 0; i < length; ++i)<br />
{<br />
value = 10 * value + (characters[i] - 48);<br />
}<br />
}<br />
return value;<br />
}<br />
Unless you're doing something abnormal, there should never be a need to mark your assembly as<br />
unsafe and take advantage <strong>of</strong> the fixed statement. The above code will easily crash (pass null as the<br />
string and see what happens), isn't nearly as feature rich as int.Parse, and in the scale <strong>of</strong> things is<br />
extremely risky while providing no benefits.<br />
<strong>Foundations</strong> <strong>of</strong> <strong>Programming</strong> Copyright © <strong>Karl</strong> <strong>Seguin</strong> www.codebetter.com<br />
62