在他的article关于“性能与懒惰”段落中的单身人士中,Jon Skeet写了以下几行:
如果您的单例实例在相对较紧的范围内被引用 循环,这可以产生(相对)显着的性能差异。
据我了解,他的意思是两种情况之间的区别:有和没有静态构造函数。
但是,尽管有这些话,但这种差异的原因对我来说仍然含糊不清:
这可以提高性能,因为它允许JIT编译器创建 单一检查(例如在方法的开头)以确保 该类型已初始化,然后从此开始承担。
如果存在静态构造函数,那么JIT编译器会做什么?
答案 0 :(得分:1)
两种方法都没有太大的性能差异。除非你在一个紧密的循环中调用它们。
单例和静态类之间的最大区别在于单例可以实现接口。你可以将单例类作为参数传递。
修改强> 的
除非你在紧密的循环中呼叫它们
单例实例变体较慢,因为您必须访问两个内存操作才能获得该值。
和正常的内存存储
但是对于正常的电话来说,差别可以忽略不计。当你在一个巨大的循环中调用它时,这种差异将会增加,而静态类在这种情况下会表现得更好。
答案 1 :(得分:0)
Jon Skeet实际上指的是在创建单例对象的实例时。如果你在静态构造函数中创建它,那么框架确保它只执行一次并且不需要取出锁。
但是,如果你在第一次访问时使用Lazy或使用一些自定义代码来生成实例,那么这可能会更慢。
他说如果你在循环中访问单例实例,那么静态构造函数会更快。
答案 2 :(得分:0)
我通过CA1810 rule explanation找到了关于效果的答案。
当一个类型声明一个显式静态构造函数时,即时 (JIT)编译器为每个静态方法和实例添加一个检查 类型的构造函数,以确保静态构造函数是 以前叫过。任何静态时都会触发静态初始化 访问成员或创建类型的实例时。 但是,如果声明a,则不会触发静态初始化 类型的变量但不使用它,如果是的话,这可能很重要 初始化改变全局状态。当所有静态数据都是 初始化内联并且未声明显式静态构造函数, Microsoft中间语言(MSIL)编译器添加了 beforefieldinit标志和隐式静态构造函数,其中 将静态数据初始化为MSIL类型定义。当JIT 编译器遇到beforefieldinit标志,大部分时间都是 不添加静态构造函数检查。静态初始化是 保证在访问任何静态字段之前的某个时间发生 但不是在调用静态方法或实例构造函数之前。 请注意,静态初始化可以在变量之后的任何时间发生 声明了类型。