NSKBpro
NSKBpro

Reputation: 383

Defragmentation of heap in c#?

I want to understand full complete working with heap in C#. I understand how the stack and heap work, but I didn't find any explanation (if it is possible) of heap defragmentation.

I read a lot about a problem with fragmentation when GC is allocating and deallocating memory blocks on heap.

So if someone can explain to me or give some good article about this concern and heap (memory) defragmentation.

Upvotes: 3

Views: 3033

Answers (1)

Dave Black
Dave Black

Reputation: 8009

If you know about how the heap works, I assume you know that there are several different kinds of heaps. See my answer here - Stack vs. Heap in .NET

So the 2 you are speaking of out of those I mention in that answer are the Large Object Heap (LOH) and the GC Heap (also called Ephemeral Heap).

Generally don't need to worry about heap fragmentation for .NET. GC for .NET works in 3 steps: mark, sweep, compact. Mark - scans for all rooted references and makes a list of those that are rooted - these are not eligible for garbage collection and will not be touched. Sweep - clears the memory for those items not on the list and clears the "marked bit" for items that were marked. Compact - moves the memory for the remaining rooted objects so it is in a contiguous block. One caveat to the Compact phase is that the LOH is NOT compacted at least as of the latest version of .NET 4.6.2. This was a design decision the CLR GC team made because of performance reasons and time it would take to move all of the memory to a contiguous block. There have been many, many performance improvements since .NET 1.0 so GC isn't the beast it used to be. In any case, the Heap for Gen 0, 1, and 2 are compacted. Thus, no need for worry about fragmentation there. For the most part, the LOH survives without fragmentation problems with the algorithm it implements. There are cases where you can get fragmentation on the LOH. This can be caused by several things - some of which are bad allocation patterns, frequent Full GC collections, etc. This can be combated by improving allocation patterns, allocating large chunks of memory as close together (programmatically) as possible, and object pooling.

As of .NET 4.5.1, there is a way to compact the LOH manually though I would strongly recommend against it for the reason that it is a huge performance hit for your app for 2 reasons:

  1. it is time consuming
  2. it clears any of the allocation pattern algorithm that the GC has collected over the lifetime of your app. While your app is running, the GC actually tunes itself by learning how your app allocates memory. As such, it becomes more efficient (to a certain point) the longer your app runs. When you execute GC.Collect() (or any overload of it), it clears all of the data the GC has learned - so it must start over. You can read more about how to manually compact the LOH here: https://blogs.msdn.microsoft.com/mariohewardt/2013/06/26/no-more-memory-fragmentation-on-the-net-large-object-heap/ (again, I recommend against it)

Info about GC mark, sweep, compact - https://blogs.msdn.microsoft.com/abhinaba/2009/01/30/back-to-basics-mark-and-sweep-garbage-collection/

Info about LOH allocation algorithm: https://www.red-gate.com/simple-talk/dotnet/net-framework/the-dangers-of-the-large-object-heap/

Upvotes: 6

Related Questions