Condividi tramite


In ngen’ed assemblies, static field initializers don’t run until the field is first accessed

Interesting fact that I discovered today: usually, static field initializers run whenever the parent type is first loaded. However when you ngen the assembly, apparently you can load the type and work with it – static field initializers will only be executed immediately before you actually access the field.

I’ve run into this by having a static Stopwatch timer = Stopwatch.StartNew(); in one of my types. It was supposed to measure an application’s startup time, but I noticed that after NGEN’ing the assembly the timer always returned a value close to 0.

Here’s the code to verify this behavior:

 using System;
 
class Program
{
    private static int field = Initialize("Field initializer");
 
    static void Main(string[] args)
    {
        Initialize("Main");
        field = 1; // touch the field
    }
 
    private static int Initialize(string message)
    {
        Console.WriteLine(message + ": " + DateTime.Now.Ticks.ToString());
        return 0;
    }
}

This works the same for .NET 4.0 SP1 for Debug/Release and x86/x64. I didn’t try other frameworks/OS/platforms.

Here’s the output from the console:

 E:\>NgenedStaticFieldInitializers.exe
Field initializer: 634462768999291588
Main: 634462768999321594

E:\>NgenedStaticFieldInitializers.exe
Field initializer: 634462769013544438
Main: 634462769013574444

E:\>ngen install NgenedStaticFieldInitializers.exe
Microsoft (R) CLR Native Image Generator - Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Installing assembly E:\NgenedStaticFieldInitializers.exe
1>    Compiling assembly E:\NgenedStaticFieldInitializers.exe (CLR v4.0.30319) .
..
1>NgenedStaticFieldInitializers, Version=1.0.0.0, Culture=neutral, PublicKeyToke
n=null 

E:\>NgenedStaticFieldInitializers.exe
Main: 634462769095630852
Field initializer: 634462769095660858

E:\>NgenedStaticFieldInitializers.exe
Main: 634462769108903506
Field initializer: 634462769108933512

Comments

  • Anonymous
    July 14, 2011
    I believe all static field initializers will run at the same time - but when that occurs is only guaranteed to be "before the first static field access or constructor call" unless you've got a static constructor, which changes the timing a bit. All of this changed (in implementation) in .NET 4 - I wasn't aware that ngen makes the situation even more complicated though. I wonder whether that is mostly about the entry point type rather than other types... Here's my write-up from a while ago: msmvps.com/.../type-initialization-changes-in-net-4-0.aspx

  • Anonymous
    July 15, 2011
    From what I understand, and I can't find the blog post that i always refer to when dealing with static initializers, is that the timing of static field initializers is undefined unless you have a static constructor. The only thing that is guarenteed without a static constructor is that the field will be initialized before it's first accessed. With a static constructor the static fields are initialized before the static contructor is executed. This all has something to do with BeforeFieldInit, and this post is the closest I found to a decent explanation : www.satyakomatineni.com/.../display

  • Anonymous
    July 26, 2011
    Thanks for the great info, guys!