Search code examples
c#garbage-collection

c# - Why does the running benchmark not show the memory allocation for the new String?


Why does running the benchmark on the code below, show no memory allocation on method BuildString? I don't get it, because as far as I know the string should be allocated on the heap.

   [MemoryDiagnoser]
   public class StringBenchmark
   {
       [Benchmark]
       public string BuildString()
       {
           return "Test";
       }

       [Benchmark]
       public string BuildStringUsingStringConcatenationMethod()
       {
           return string.Concat("Hello", 2022, "/", 5);
       }
   }

The benchmark results:

Method Mean Error StdDev Gen0 Allocated
BuildString 0.0000 ns 0.0000 ns 0.0000 ns - -
BuildStringUsingStringConcatenationMethod 60.0764 ns 0.4336 ns 0.3385 ns 0.0286 240 B

Solution

  • The compiler is free to use "interned" strings for literals, i.e. every time you use "abc" in your code, it can use the same instance of "abc". This includes expressions that the compiler can evaluate to constants during build, for example concatenation of other constant expressions.

    You can check this:

    using System;
    
    string a = Strings.Fixed(), b = Strings.Fixed(),
        c = Strings.New(), d = Strings.New();
    
    // writes "abc; equal? True; same? True"
    Console.WriteLine($"{a}; equal? {string.Equals(a,b)}; same? {ReferenceEquals(a,b)}");
    
    // writes "def; equal? True; same? False"
    Console.WriteLine($"{c}; equal? {string.Equals(c,d)}; same? {ReferenceEquals(c,d)}");
    
    static class Strings
    {
        // returns interned instance
        public static string Fixed() => "abc";
        // creates a new instance each time
        public static string New() => new string("def".AsSpan());
    }
    

    see it running