Home > Software design >  Can't find code example of stack vs heap performance?
Can't find code example of stack vs heap performance?

Time:07-23

I'm working on a research paper about stack vs heap. I have found a lot of information about the stack but not a lot about the heap?

I was searching deeply to find an example or to create an example to show performance difference between the stack and the heap.

But I have not found any code example. I is it possible to provide some code that can show me the performance difference between the stack and the heap in c#?

CodePudding user response:

The performance difference between the two is a lot to do with implementation. The CLR is a virtual machine, which means it creates an abstraction of a computer over the actual hardware and operating system to provide a better programming experience. Therefore a lot of real things we have in our processor like register aren't visible to us.

There are a few guarantees though, for example, we know that local structs are stack allocated, and classes are heap allocated. We also know that the heap requires garbage collection and memory allocation (once the allocated data excedes a certain size to cause enough memory pressure for the CLR to allocate a new segment) whereas the stack is pre-allocated per thread. Does this give us a performance difference? It depends how you develop, a lot of times using stack allocated structs can make your program slower, eg by passing data by value which requires expensive copies rather than passing a single reference. For an example of a performance difference see this:

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Loggers;

namespace StackVsHeap
{
    public class Program
    {
        public static void Main(string[] args)
        {
            RunBenchmarks();
        }

        public static void RunBenchmarks()
        {
            var config = new ManualConfig()
                .AddLogger(ConsoleLogger.Default)
                .AddColumn(TargetMethodColumn.Method, StatisticColumn.Median, StatisticColumn.StdDev,
                    StatisticColumn.Q1, StatisticColumn.Q3, new ParamColumn("Size"));
            BenchmarkDotNet.Running.BenchmarkRunner.Run<ExampleBenchmark>(config);

        }
    }

    [ShortRunJob]
    public class ExampleBenchmark
    {
        [Benchmark]
        public void BenchmarkHeap()
        {
            long y = 0;
            for (int i = 0; i < 100000; i  )
            {
                var x = new TestClass(1,2,3,4);
                y=y&x.CalculateXor();
            }
        }

        [Benchmark]
        public unsafe void BenchmarkStack()
        {
            long y = 0;
            for (int i = 0; i < 100000; i  )
            {
                var x = new TestStruct(1, 2, 3, 4);
                y = y & x.CalculateXor();
            }
        }
    }

    public record TestClass(long a, long b, long c, long d)
    {
        public long CalculateXor()
        {
            return a ^ b ^ c ^ d;
        }
    }
    public record struct TestStruct(long a, long b, long c, long d)
    {
        public long CalculateXor()
        {
            return a ^ b ^ c ^ d;
        }
    }

}

The stack allocated example requires 0 heap allocations and is all performed in the thread stack which is allocated on startup. Therefore there is almost no allocation cost and also no object header. In addition the memory allocated for the TestStruct is freed as soon as the loop is exited by simply decrementing the stack pointer, whereas for the TestClass it will only be freed through GC, so int he stack example you're continually hitting the same address which is far more likely to be in the CPU cache.

Here is the result of the above benchmark measured with Benchmark.NET:

|         Method |   StdDev |    Median |        Q1 |        Q3 |
|--------------- |---------:|----------:|----------:|----------:|
|  BenchmarkHeap | 5.947 us | 342.12 us | 338.34 us | 344.20 us |
| BenchmarkStack | 0.028 us |  20.79 us |  20.77 us |  20.80 us |

This is a roughly 15x difference.

  • Related