3

在“性能与懒惰”段落中关于单例的文章中,Jon Skeet 写道:

如果您的单例实例在相对紧凑的循环中被引用,这可能会产生(相对)显着的性能差异。

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

但是,尽管有这些话,但对我来说,这种差异的原因仍然很模糊:

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

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

4

3 回答 3

1

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

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

编辑


除非你在一个紧密的循环中调用它们

单例实例变体较慢,因为您必须访问两个内存操作才能获得该值。

  1. 静态存储

  2. 和正常的内存存储

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

于 2013-05-08T10:27:16.953 回答
0

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

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

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

于 2013-05-08T10:00:42.920 回答
0

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

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

于 2013-07-05T09:52:24.093 回答