15.01.2013 Views

Foundations of Programming - Karl Seguin

Foundations of Programming - Karl Seguin

Foundations of Programming - Karl Seguin

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!