静态方法更有效率吗?
在内存和时间方面,静态方法更好吗?
通常是的,没有必要传递“this”引用。 该引用在ECX寄存器中传递,因此不需要额外的堆栈空间。 如果您使用同一个类的实例方法调用该寄存器,则该寄存器已经设置完毕,根本没有任何储蓄。 但是当方法在另一个类中时,它可以帮助缓解x86 CPU内核的压力,而x86没有很多寄存器。 看到一个可衡量的性能改善将是非常罕见的。
我虔诚地将不使用实例成员的类的方法标记为静态。 我重视静态关键字提供的内在契约:“这个方法不会改变对象的状态”。
你应该让一个方法是静态的,如果它不需要它所属类的任何状态信息的话。
如果你不关心多态性 ,只要决定是否将类实例成员作为parameter passing给方法,就可以将任何方法编写为实例或静态方法。 你应该考虑的是,语法是否是自然的,代码是否容易理解和有意义,等等。
您可能不应该担心在这个级别进行优化,因为实例与静态方法的性能开销可以忽略不计。 是的,在调度表中有一些用于types的空间(如果方法是虚拟的) – 但是这是一个微小的,不变的开销。 是的,调用一个实例方法和一个静态方法也有一点小小的开销 – 但是它又很小。
这似乎是一个微观优化的水平,除非你有可衡量的,有形的证据才能真正地影响到项目绩效,否则你应该避免。 事实上,如果你做错了,传入额外参数的代价(复制到堆栈等),而不是通过隐藏this
types的引用来访问它们, this
可能会导致性能下降。
你最好分析方法的语义,并在此基础上作出静态/实例的决定。
如果你打算传入实例( SomeStaticMethod(obj, "abc", 123);
),那么不是真的。 你只能在没有多态的场景中使用静态方法,在这种情况下,任何简单的东西(比如属性)都可能被内联了。
使用对象“自然”( obj.SomeMethod("abc",123);
) – 保持代码简单,并find性能问题的configuration文件 – 这是不太可能在实例和静态之间的区别,除非你运行一些非常紧圈。 有一些情况可能很重要,但它们很专业。
静态方法和非虚拟实例方法几乎没有区别。 后者只是把this
引用/引用当作一个“隐藏的”论点。 在生成的机器代码中,这两种调用看起来非常相似。
如果方法不依赖/修改对象,方法应该是静态的。
另一方面,虚拟方法(可重写)需要调用者在所谓的vtable中查找确切的实现。 除了防止编译器内联非常小的方法(简单的属性访问器经常内联)之外,查找需要几个周期。
尽pipe如此,虚拟方法是CLR中C#中可用的最快的一种dynamic分派。 比代表和反思快得多。
这类问题有很多。 静态方法是更快还是更慢? 虚拟函数是更快还是更慢? 我++比++更快/更慢吗? 是(;;)比while(true)更快/更慢?
抓住一些软件并调整它是值得的。 在实践中,这会让你很好地理解实际影响软件性能的事物。
那么你会看到这样的问题的答案(大部分时间)是微不足道的。
如果我能概括一下,根据我的经验,使软件变慢的事情是使用看起来无辜的代码行,但其时间消耗可能比想象的大几个数量级。 由于他们看起来无辜,所以通过查看代码是无法可靠地发现的。 示例:重复分配,初始化和取消分配大型数据结构,以确保它们存在。 将不需要的string国际化。 通知风格的编程,可以将一个简单的属性设置变成一个庞大的数据结构的方法调用级联。 简单的O(n ^ 2)操作,除了n变大之外永远不会成为问题。 认为(a <b)花费大约相同的时间长度,不pipea和b是整数还是大类。 这个“看上去无辜的时间倍增”在多层抽象上有复合的效果,所以大型的软件往往会被它吞噬,就我的经验而言。
在大多数情况下,这种差异是可以忽略的,但静态更有效。
在一个静态方法调用中可以避免以下步骤:
- 检查对象引用(this)是否为空。
- 在虚拟调度表上find正确的方法。
- 将对象引用放置在堆栈上。
我发现我在一个给定的类中编写的许多实用方法只需要在这个类中有几个数据成员,或者根本不需要。 在这些情况下,我倾向于将这些方法编写成(独立的)静态方法,直接传入他们需要的less数数据项。
如果它们对其他课程特别普遍而且有用,我也可以把它们公诸于众。