CLR如何知道静态字段是否已经初始化?

时间:2016-03-11 11:07:30

标签: c# .net clr cil static-initialization

有一件事我一直想知道static fields / constructors

static class首次引用其中一个字段时进行初始化,这很容易。

但CLR如何知道这是第一次?

2 个答案:

答案 0 :(得分:3)

CLR维护一个包含已加载的所有类型及其初始化状态的表。如果A使用B的静态字段,则CLR知道A正在使用B,并且在初始化A时,它也会初始化B }。因此,不会对每次访问执行是否初始化依赖项的检查。通过类型的依赖图确保它。

如果您对实施细节感兴趣,可以查看CoreCLRIsClassInitialized的{​​{1}}方法及其usage时创建类实例的方法

我希望这能回答你的问题。

答案 1 :(得分:2)

  

第一次引用其中一个字段时static class初始化,这很容易。

不,这不是那么简单。如果忽略方法调用,则static类必须在第一次访问其中一个字段之前初始化,如果它未标记为beforefieldinit。如果它标记为beforefieldinit,则可以在此之前初始化它。 (Jon Skeet有an article with lots more information about beforefieldinit。)

这会影响何时检查类初始化?由于CLR使用JIT编译,因此它在JIT编译方法时检查类初始化。如果该类标记为beforefieldinit且尚未初始化,则JIT编译器会立即对其进行初始化。然后它实际上编译了方法,它可以假定该类已经初始化,因此不需要检查。

如果没有beforefieldinit,如果类尚未初始化,则JIT编译器必须发出代码,在每次潜在的第一次字段访问之前检查初始化。但是如果该类已经初始化并且另一个方法正在编译JIT,则JIT编译器不再需要在那里发出检查。

在某些情况下,这会对性能产生负面影响。从上面可以清楚地看到,要防止出现这种情况,您需要确保将有问题的类标记为beforefieldinit。从C#开始的方法是没有static构造函数,只使用static字段初始值设定项。