What does beforefieldinit flag do?
Asked Answered
F

4

91

What does beforefieldinit flag do? When I look into the IL of my class I see this flag but I don't know what this flag is actually doing?

Fabianfabianism answered 4/3, 2009 at 14:29 Comment(0)
L
148

See my article on this very issue.

Basically, beforefieldinit means "the type can be initialized at any point before any static fields are referenced." In theory that means it can be very lazily initialized - if you call a static method which doesn't touch any fields, the JIT doesn't need to initialize the type.

In practice it means that the class is initialized earlier than it would be otherwise - it's okay for it to be initialized at the start of the first method which might use it. Compare this with types which don't have beforefieldinit applied to them, where the type initialization has to occur immediately before the first actual use.

So, suppose we have:

public static void DoSomething(bool which)
{
    if (which)
    {
        FirstType.Foo();
    }
    else
    {
        SecondType.Bar();
    }
}

If both types have beforefieldinit applied to them (which in C# they do by default unless the type has a static constructor) then they'll both be initialized at the start of the DoSomething method (usually - it's not guaranteed). If they don't have beforefieldinit then only one of them will be initialized, based on the flag.

This is why it's common to use a static constructor (even an empty one!) when implementing the singleton pattern.

Lyndsaylyndsey answered 4/3, 2009 at 14:33 Comment(9)
"the type can be initialized at any point before any fields are referenced." is it also true for running static methods ?Flung
@RoyiNamir, the CLI spec says that if the BeforeFieldInit is applied then "the type's initializer method is executed at, or sometime before, first access to any static field defined for that type". If that attribute is missed(static .ctor) then "first access to any static or instance field of that type, or first invocation of any static, instance or virtual method of that type". So it's not true for BeforeFieldInit applied unless the static method references another static field.Cripps
I discovered that there is a performance penalty for using static constructors (i.e. classes that do not have the beforefieldinit flag). If you call static members of a certain class frequently, it seems that the runtime has to do an extra check before each call, to test whether the type has been initialized yet; beforefieldinit avoids these checks. A couple of benchmarks were about 50% faster with beforefieldinit: codeproject.com/Articles/87991/…Jahdiel
I still don't understand. I arrived here from csharpindepth.com/articles/singleton. In the fourth example of creating an instance of a Singleton, the comments in the code are // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit But doesn't a singleton ALWAYS make only one of itself? What is gained by use of checking beforefieldinit flag? Seems superfluous but I'm not the most intricately educated C# developer. I do get that applying the flag makes certain of one ... isn't this overkill?Lubricity
@user1585204: It's not about whether it "makes only one of itself" - it's about changing the potential timing. See csharpindepth.com/articles/BeforeFieldInit for more details about what BeforeFieldInit does. Without the static constructor, the singleton might be initialized even if you never actually go down a code path that uses it.Lyndsaylyndsey
Let's say that I have a helper static class that has only public methods to do some work around for example strings (no private methods/properties, only public methods). Methods in that class work only on passed arguments OR are calling some other types. So for such case scenario it would be good to put the static constructor in order to get better performance?Crowded
@Eru: No, a static constructor reduces performance (very slightly; unnoticeably in most cases) by enforcing a specific initialization ordering.Lyndsaylyndsey
@JonSkeet So now I am a little confuse and please forgive me for asking again: If the class has a static constructor then the class is NOT marked with "beforefieldinit". So from your example if FirstType has a static constructor (not marked with beforefieldinit) and the SecondType does NOT have a static constructor (marked with beforefieldinit), then I understand that invokation of FirstType will be faster?Crowded
@Eru: No, it means access to SecondType will be (very very slightly) faster, because it allows the JIT more leeway in terms of how it handles initialization. Forget about the beforefieldinit details; stick to just the C# abstraction layer: the presence of a static constructor makes a guarantee about exactly when the type will be initialized, which means the JIT can't generate code that's quite as optimized.Lyndsaylyndsey
C
7

Looks like it is going to change in 4.6

https://github.com/dotnet/coreclr/issues/1193

Chaffin answered 4/7, 2015 at 13:26 Comment(3)
Awesome, so does this mean it'll wait until the very last moment to initialize the field (regardless of whether it has beforefieldinit or not)?Gage
Before the first use all the accesses will be prefixed with initialization check. After that, when other methods are jitted, the generated code will access the field directly. If it is of a primitive type then it can even be used as a JIT time constant.Chaffin
Jon's detailed analysis on changes to type initialization starting .Net 4.0 here.Trass
B
3

Quote from “CA1810: Initialize reference type static fields inline (code analysis) - .NET | Microsoft Docs” with emphasis mine and TL;DR at the bottom:

When a type declares an explicit static constructor, the just-in-time (JIT) compiler adds a check to each static method and instance constructor of the type to make sure that the static constructor was previously called. Static initialization is triggered when any static member is accessed or when an instance of the type is created. However, static initialization is not triggered if you declare a variable of the type but do not use it, which can be important if the initialization changes global state.

When all static data is initialized inline and an explicit static constructor is not declared, Microsoft intermediate language (MSIL) compilers add the beforefieldinit flag and an implicit static constructor, which initializes the static data, to the MSIL type definition.

When the JIT compiler encounters the beforefieldinit flag, most of the time the static constructor checks are not added. Static initialization is guaranteed to occur at some time before any static fields are accessed but not before a static method or instance constructor is invoked. Note that static initialization can occur at any time after a variable of the type is declared.

Static constructor checks can decrease performance. Often a static constructor is used only to initialize static fields, in which case you must only make sure that static initialization occurs before the first access of a static field. The beforefieldinit behavior is appropriate for these and most other types. It is only inappropriate when static initialization affects global state and one of the following is true:

  • The effect on global state is expensive and is not required if the type is not used.

  • The global state effects can be accessed without accessing any static fields of the type.

TL;DR: beforefieldinit flag helps avoid static constructor checks, which helps in performance (since the checks can affect performance). It does this by telling the JIT to run static constructors before the actual static field usage.

Bradford answered 10/2, 2022 at 11:1 Comment(0)
G
0

If marked BeforeFieldInit then the type's initializer method is executed at, or sometime before, first access to any static field defined for that type.

If not marked BeforeFieldInit then that type's initializer method is executed at first access to any static or instance field of that type, or first invocation of any static, instance or virtual method of that type.

Goldenrod answered 14/3, 2021 at 17:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.