.NET pre-allocating memory vs ad-hoc allocation – Education Career Blog

I’m working on some applications that require very low latency and push a lot of memory and was doing some testing of how e.g. allocating a list ad-hoc vs. pre-allocating and clearing a list performs.
I was expecting the test runs that pre-allocate the memory to perform a lot faster but to my surprise they’re actually slightly slower (when I let the test run for 10 minutes, the avg. difference is about 400ms).

Here is the test code that I used:

    class Program
{
    private static byte buffer = new byte50;
    private static List<byte> preAlloctedList = new List<byte>(500);

    static void Main(string args)
    {
        for (int k = 0; k < 5; k++)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < 1000000; i++)
            {
                List<byte> list = new List<byte>(300);

                for (int j = 0; j < 300; j++)
                {
                    list.Add(buffer);
                }
            }

            sw.Stop();
            Console.WriteLine("#1: " + sw.Elapsed);
            sw.Reset();
            sw.Start();

            for (int i = 0; i < 1000000; i++)
            {
                for (int j = 0; j < 300; j++)
                {
                    preAlloctedList.Add(buffer);
                }

                preAlloctedList.Clear();
            }
            sw.Stop();
            Console.WriteLine("#2: " + sw.Elapsed);
        }

        Console.ReadLine();
    }
}

Now, what’s really interesting, I was running perfmon side by side and saw the following pattern which looks like I expected:

Green = Gen 0 collections
Blue = Allocated Bytes/sec
Red = %Time in GC

The console application below shows the test runtimes for #1 and #2
alt text

So, my question is, why is Test #1 faster than #2?
Obviously, I’d rather have the perfmon statistics of Test #2 in my app as there is basically no memory pressure, no GC collections, etc. yet #1 seems to be slightly faster?
Does List.Clear() carry that much overhead?

Thanks,

Tom

EDIT
I did another test, with the same setup but running the app with server GC enabled, now #2 becomes slightly faster
alt text

,

I suspect the reason Test #1 is faster is that the garbage collection is happening on a separate thread, and the overhead of allocation is lower than the extra List<T>.Clear call. Since none of these lists are large (just 300 references each), and they’re all being created and unrooted in a tight loop, they’ll all typically stay in Gen 0.

I’ve noticed this during profiling in the past – reusing a List<T> and calling Clear on it is often slower than just reallocating. Clear() actually clears the internal array as well as resets the parameters of the list, which I believe has (slightly) more overhead than the initial allocation of the list.

However, this example, in my opinion, really just shows that the GC in .NET is very, very efficient.

,

Does List.Clear() carry that much overhead?

Yes, compared to a (single) GC.Collect(0) , doing a few thousand calls to Clear() might very well be slower.

For what I have learned, the dotNet memory system is very fast in allocating/deallocating shortlived memory blocks.

But be careful to carry conclusions from this simple test over to your real app.

Leave a Comment