How to get allocations in .NET? And how big is an empty array?

20/11/2022
C#.NET

Often times we hear about allocations on the heap. How can we easily measure this? This article will show you a very easy way of doing so.

Plus we will answer the question how big is an empty array? And if you think 0 bytes, then spoiler alert, that is not the case at all.

Getting allocations of the current thread

.NET itself brings a very convenient helper with the GC-class. GC is short for Garbage Collector, as he manages all of your heap allocations in the first place. If that does not ring a bell for you, here is a small overview how the GC works: The garbage collector in .NET.

So we can write code like this to measure our allocations:

var before = GC.GetAllocatedBytesForCurrentThread();

var list = new int[0];
var after = GC.GetAllocatedBytesForCurrentThread();

Console.WriteLine($"Used bytes: {after - before}");

Which would print Used bytes: 24 on my local machine (.NET7 MacBook M1 Pro). Hupps? Why does an empty array have some allocations? The reason is simple, each of your arrays is of type Array and Array has some fields to hold some information like: int Length (4 bytes), long LongLength (8 bytes), int Rank (4 bytes) plus a void* elementType, which is 8 bytes on 64 bit. That makes all in all: 24 bytes!

Pro-Tip: If you are using Array<T>.Empty then you will re-use the same static instance everywhere. That means you are only allocating once 24 bytes and not over and over again. Plus it is more readable.

GC.GetAllocatedBytesForCurrentThread() will return the cumulative total of bytes allocated by the current thread. So even if the GC would have run, this will show how many allocations are done in total. That can be good or bad.

You can simulate such behavior, where you don't want to take the garbage collector into account with the following code:

GC.TryStartNoGCRegion(1_000_000);
// Your code
GC.EndNoGCRegion();

GC.TryStartNoGCRegion(1_000_000); will enter a region where the GC will try not to run. You have to pass in a size, you can allocate before it performs a GC cycle. You can only enter "one" region. So nested calls will result in an exception. It is also critical to call GC.EndNoGCRegion(); at the end. So normally you would wrap your calls in a try-catch fashion, where you would call GC.EndNoGCRegion in the final part.

2
Buy Me a Coffee at ko-fi.com
An error has occurred. This application may no longer respond until reloaded. Reload x