Perf penalty Static Constructor

There was a thread recently over the CLR perf alias that I thought I’d share.

One of the WinFX developers asks if there is any perf differences between these two classes:

public class Foo1 {

   public static int Value = 42;

}

public class Foo2 {

   static Foo2 () {

      Value = 42;

   }

   public static int Value;

}

The two classes do essentially the same thing: initialize “Value” to 42 before anyone can access it. But Foo1 is the more preferred way. Why, because explicit static constructors are expensive because they require that the runtime to insure that the value is set exactly before any member of the class is accessed. The exact cost is depends on the scenario, but it can be quite noticeable in some cases.

But why is Foo1 better? After all, when we look at the IL, we find out that they BOTH have static constructors that look identical. In the case of Foo1, the C# compiler added for you.

            //Foo1 static constructor

.method private hidebysig specialname rtspecialname static

        void .cctor() cil managed

{

  // Code size 8 (0x8)

  .maxstack 1

  IL_0000: ldc.i4.s 42

  IL_0002: stsfld int32 Foo1::Value

  IL_0007: ret

} // end of method Foo1::.cctor

//Foo2 static constructor

.method private hidebysig specialname rtspecialname static

        void .cctor() cil managed

{

  // Code size 8 (0x8)

  .maxstack 1

  IL_0000: ldc.i4.s 42

  IL_0002: stsfld int32 Foo2::Value

  IL_0007: ret

} // end of method Foo2::.cctor

 

The secret? Yet another little metadata mark that the C# compiler emits for in the Foo1 case called beforeFieldInit.

.class public auto ansi beforefieldinit Foo1

This bit tells the runtime it can be a little bit lazy and only run the static constructor when a static member is accessed, not anytime a member of the class is accessed. As we all know as developers being lazy is faster!

So what? Avoid using explicit static constructors if you can avoid it (perf Foo1 style code to Foo2 style code).

Some good info on the web on this topic… Our perf team pointed to this nice article: https://www.ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html

And I found this site has very useful quotes from the CLI Spec:

https://www.yoda.arachsys.com/csharp/beforefieldinit.html