Static constructor code runs slower

I noticed that the startup time may vary depending on where I placed part of the initialization code. I thought it was really strange, so I wrote a small benchmark that confirmed my suspicions. It seems that the code executed before calling the main method is slower than usual.

Why Benchmark(); works at different speeds depending on whether it is called before and after regular code?

Here is the reference code:

 class Program { static Stopwatch stopwatch = new Stopwatch(); static Program program = new Program(); static void Main() { Console.WriteLine("main method:"); Benchmark(); Console.WriteLine(); new Program(); } static Program() { Console.WriteLine("static constructor:"); Benchmark(); Console.WriteLine(); } public Program() { Console.WriteLine("public constructor:"); Benchmark(); Console.WriteLine(); } static void Benchmark() { for (int t = 0; t < 5; t++) { stopwatch.Reset(); stopwatch.Start(); for (int i = 0; i < 1000000; i++) IsPrime(2 * i + 1); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds + " ms"); } } static Boolean IsPrime(int x) { if ((x & 1) == 0) return x == 2; if (x < 2) return false; for (int i = 3, s = (int)Math.Sqrt(x); i <= s; i += 2) if (x % i == 0) return false; return true; } } 

The results show that Benchmark() works almost twice as slow for both the static constructor and the constructor for the static Program program property:

 // static Program program = new Program() public constructor: 894 ms 895 ms 887 ms 884 ms 883 ms static constructor: 880 ms 872 ms 876 ms 876 ms 872 ms main method: 426 ms 428 ms 426 ms 426 ms 426 ms // new Program() in Main() public constructor: 426 ms 427 ms 426 ms 426 ms 426 ms 

Doubling the number of iterations in the reference loop forces all times to double, assuming that the resulting performance failure is not a constant, but a factor.

 // static Program program = new Program() public constructor: 2039 ms 2024 ms 2020 ms 2019 ms 2013 ms static constructor: 2019 ms 2028 ms 2019 ms 2021 ms 2020 ms main method: 1120 ms 1120 ms 1119 ms 1120 ms 1120 ms // new Program() in Main() public constructor: 1120 ms 1128 ms 1124 ms 1120 ms 1122 ms 

Why is this so? It would be wise if initialization were as fast, if it was done where it belongs. Testing was performed in .NET 4, release mode, optimization enabled.

+7
source share
2 answers

This is a very interesting problem. I spent some time experimenting with your program options. Here are a few notes:

  • If you move the static Benchmark () method to another class, performance for the static constructor is reduced.

  • If you make the Benchmark () method in the instance method, then the performance penalty will disappear.

  • When I look at your fast cases (1, 2) and your slow cases (3, 4), the slow cases spent extra time in CLR helper methods, in particular JIT_GetSharedNonGCStaticBase_Helper.

Based on this information, I can talk about what is happening. The CLR must ensure that each static constructor runs no more than once. The complication is that static constructors can form a loop (for example, if class A contains a static field of type B and class B contains a static field of type A).

When executed inside a static constructor, the JIT compiler insert checks some calls to static methods to prevent potential infinite loops due to cyclical class dependencies. When the static method is called from outside the static constructor, the CLR recompiles the method to remove the checks.

This should be very close to what is happening.

+3
source

This is a very well documented fact.

Static constructors are slow. .Net runtimes are not smart enough to optimize them.

refer: Decreased performance of static constructors

explicit static constructors are expensive because they require runtime to ensure that the value is set exactly before accessing any member of the class. The exact cost depends on the scenario, but in some cases this may be noticeable.

+3
source

All Articles