有和没有静态构造函数的静态类型性能

本文关键字:静态 类型 性能 静态类 构造函数 | 更新日期: 2023-09-27 18:12:41

在他关于单例的文章"性能vs懒惰"一段中,Jon Skeet写道:

如果你的单例实例在一个相对紧密的循环,这会产生(相对)显著的性能差异。

根据我的理解,他指的是两种情况之间的区别:有静态构造函数和没有静态构造函数。


尽管我说了这些话,但造成这种差异的原因我仍然很模糊:

这可以提高性能,因为它允许JIT编译器生成一个单次检查(例如在方法开始时)以确保类型已经初始化,然后从那时起假定它。

如果静态构造函数存在,jit编译器做什么?

有和没有静态构造函数的静态类型性能

两种方法的性能差异不大。除非你在一个紧密的循环中调用它们。

单例类和静态类的最大区别在于单例类可以实现接口。你可以把单例类作为参数传递。

编辑


除非你在紧循环中调用它们

单实例的变体速度较慢,因为必须访问两次内存操作才能获得值。

  1. 静态存储
  2. 和正常内存存储

    但是对于一个正常的调用,这是可以忽略不计的差异。当你在一个巨大的循环中调用它时,这种差异将会增加,在这种情况下静态类将会表现得更好。

Jon Skeet实际上指的是当您创建单例对象的实例时。如果你在静态构造函数中创建它,那么框架将确保它只执行一次,并且不需要取出锁。

但是,如果您使用Lazy或使用一些自定义代码在第一次访问实例时生成实例,那么这可能会变慢。

他是说如果你在循环中访问单例实例,那么静态构造函数会更快。

我通过CA1810规则解释找到了关于性能的答案。

当一个类型声明了一个显式的静态构造函数时(JIT)编译器为每个静态方法和实例添加检查构造函数的类型,以确保静态构造函数是之前调用。静态初始化被触发,当任何静态成员访问或创建该类型的实例时。但是,如果声明了变量的类型,但不要使用它,如果初始化改变全局状态。当所有的静态数据内联初始化且未声明显式静态构造函数,Microsoft中间语言(MSIL)编译器添加了Beforefieldinit标志和隐式静态构造函数,其中将静态数据初始化为MSIL类型定义。当JIT编译器遇到beforefieldinit标志,大多数情况下没有添加静态构造函数检查。静态初始化是保证在访问任何静态字段之前的某个时间发生但不是在调用静态方法或实例构造函数之前。注意,静态初始化可以在变量之后的任何时间发生