ZinSunrise
ZinSunrise

Reputation: 13

Why is there no extra memory allocation

When I was conducting the following benchmark test, the benchmark information indicated that there was no additional memory allocation. However, doesn't converting a struct to an interface involve boxing?

        [MemoryDiagnoser]
        public class Test
        {
            [Benchmark]
            public Color Test123()
            {
                Color color = new Color();
                IFormattable formattable = color;
                return (Color)formattable;
            }

            [Benchmark]
            public int Test234()
            {
                int number = 114514;
                IConvertible convertible = number;
                return (int)convertible;
            }
        }
 


    [StructLayout(LayoutKind.Sequential)]
    public struct Color : IFormattable
    {
        public double R { get; set; }
        public double G { get; set; }
        public double B { get; set; }
        public double A { get; set; }

        public static Color GetRandomColor()
        {
            Random rand = new Random();
            double r = rand.Next(0, 256) * rand.NextDouble();
            double g = rand.Next(0, 256) * rand.NextDouble();
            double b = rand.Next(0, 256) * rand.NextDouble();
            double a = rand.Next(0, 256) * rand.NextDouble();

            return new Color(r, g, b, a);
        }

        public string ToString(string? format, IFormatProvider? formatProvider)
        {
            return $"{R} {G} {B} {A}";
        }

        public Color(double r, double g, double b, double a)
        {
            R = r;
            G = g;
            B = b;
            A = a;
        }
        public static bool operator ==(Color left, Color right)
        {
            return left.R == right.R && left.G == right.G && left.B == right.B && left.A == right.A;
        }

        public static bool operator !=(Color left, Color right)
        {
            return !(left == right);
        }
    }

.NET 8

result

The Color struct consists of only four double members: RGBA.

"I tried to open Rider to analyze the IL code and found that there are indeed boxing and unboxing instructions. I would like to understand why there is no additional memory allocation."

  .method public hidebysig static valuetype Program.Color
    Test123() cil managed
  {
    .maxstack 1
    .locals init (
      [0] valuetype Program.Color color,
      [1] class [System.Runtime]System.IFormattable formattable,
      [2] valuetype Program.Color V_2
    )

    // [28 9 - 28 10]
    IL_0000: nop

    // [29 13 - 29 39]
    IL_0001: ldloca.s     color
    IL_0003: initobj      Program.Color

    // [30 13 - 30 46]
    IL_0009: ldloc.0      // color
    IL_000a: box          Program.Color
    IL_000f: stloc.1      // formattable

    // [31 13 - 31 39]
    IL_0010: ldloc.1      // formattable
    IL_0011: unbox.any    Program.Color
    IL_0016: stloc.2      // V_2
    IL_0017: br.s         IL_0019

    // [32 9 - 32 10]
    IL_0019: ldloc.2      // V_2
    IL_001a: ret

  } // end of method Program::Test123

Upvotes: 1

Views: 119

Answers (1)

Ivan Petrov
Ivan Petrov

Reputation: 4935

The JIT compiler is smart enough to remove the formattable gymnastics and essentially return just the color

If you change the method to actually return IFormattable, you will have allocations:

public IFormattable Test123() {
    Color color = new Color();
    IFormattable formattable = color;
    return formattable;
}

Upvotes: 0

Related Questions