静态方法与实例方法的性能

时间:2012-09-05 10:30:54

标签: c# performance static-methods il

我的问题涉及静态方法与实例方法的性能特征及其可伸缩性。假设在这种情况下,所有类定义都在一个程序集中,并且需要多个离散指针类型。

考虑:

public sealed class InstanceClass
{
      public int DoOperation1(string input)
      {
          // Some operation.
      }

      public int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more instance methods.
}

public static class StaticClass
{
      public static int DoOperation1(string input)
      {
          // Some operation.
      }

      public static int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more static methods.
}

上述类代表帮助器样式模式。

在实例类中,解析实例方法需要花点时间与StaticClass相反。

我的问题是:

  1. 当保持状态不是问题(不需要字段或属性)时,使用静态类总是更好吗?

  2. 如果有相当多的静态类定义(例如100,每个都有许多静态方法),与相同数量的实例类定义相比,这会对执行性能或内存消耗产生负面影响

  3. 当调用同一实例类中的另一个方法时,实例解析是否仍然存在?例如,在同一个实例的this.DoOperation2("abc")内使用[this]关键字,例如DoOperation1

3 个答案:

答案 0 :(得分:135)

理论上,由于额外隐藏的this参数,静态方法应该比实例方法稍微好一点,所有其他条件都相同。

在实践中,这几乎没有什么区别,它会隐藏在各种编译器决策的噪音中。 (因此,有两个人可以证明"一个人比另一个人更好,结果不一致)。尤其是因为this通常在寄存器中传递,并且通常在该寄存器中开始。

这最后一点意味着理论上,我们应该期望一个静态方法,它将一个对象作为一个参数,并对它做一些事情,而不是作为同一个对象上的实例的等价物。尽管如此,差异是如此之小,如果你试图测量它,你可能最终会测量其他编译器的决定。 (特别是因为参考文件在整个时间内的可能性非常高)。

真正的性能差异将取决于你是否人为地将内存中的对象做成了一些自然应该是静态的东西,或者你是以复杂的方式纠缠于对象传递的链条来做什么自然应该是实例。

因此对于数字1.当保持状态不是一个问题时,静态总是更好,因为那是静态的。这不是一个性能问题,尽管有一个整体规则可以很好地与编译器优化相配合 - 更有可能是有人去优化正常使用的案例而不是那些出现的案例。奇怪的使用。

第2号。没有任何区别。每个成员都有一定数量的每类成本,它包括有多少元数据,实际DLL或EXE文件中有多少代码,以及那里有多少jitted代码。无论是实例还是静态,都是一样的。

对于第3项,thisthis一样。但请注意:

  1. this参数在特定寄存器中传递。在同一个类中调用实例方法时,它可能已经存在于该寄存器中(除非它被存储并且由于某种原因使用了寄存器)因此不需要将this设置为需要设置的是什么。这在某种程度上适用于例如方法的前两个参数是它所进行的调用的前两个参数。

  2. 由于明确this不为空,因此在某些情况下可用于优化通话。

  3. 由于它很清楚this不是null,这可能会使内联方法调用再次更有效,因为伪造方法调用所产生的代码可以省略一些null - 无论如何它可能需要它。

  4. 那就是说,空检查很便宜!

  5. 值得注意的是,作用于对象而非实例方法的泛型静态方法可以减少http://joeduffyblog.com/2011/10/23/on-generics-and-some-of-the-associated-overheads/中讨论的一些成本,在这种情况下,给定的静态不会被调用给定的类型。正如他所说的那样,不过,事实证明,扩展方法是使通用抽象更加付费的好方法。"

    然而,请注意,这仅涉及该方法使用的其他类型的实例化,否则不存在。因此,它实际上并不适用于很多情况(某些其他实例方法使用该类型,其他一些其他代码使用该类型)。

    要点:

    1. 大多数情况下,实例与静态的性能成本可以忽略不计。
    2. 通常会有滥用静电的成本,反之亦然。如果您不在静态和实例之间做出决定,那么您更有可能获得正确的结果。
    3. 在极少数情况下,另一种类型的静态泛型方法导致创建的类型少于实例泛型方法,这可以使有时具有很少的好处来转为很少使用(和&# 34;很少"指的是它在应用程序的生命周期中使用的类型,而不是它被调用的频率。一旦你得到了他在那篇文章中所谈论的内容,你就会发现它无论如何都与大多数静态vs实例决策无关。编辑:它主要只有ngen的成本,而不是jitted代码。
    4. 编辑:关于如何便宜的空检查的说明(我在上面声称)。 .NET中的大多数空值检查根本不检查空值,而是继续它们将要做的事情,假设它可以工作,如果发生访问异常,它会变成{ {1}}。因此,大多数情况下,当C#代码因为访问实例成员而涉及空检查时,如果成功则成本实际为零。一个例外是一些内联调用,(因为他们希望表现得好像他们调用了一个实例成员)并且他们只是按一个字段来触发相同的行为,因此它们也非常便宜,但它们仍然经常被遗漏(例如,如果方法的第一步涉及访问字段)。

答案 1 :(得分:6)

  

保持状态不是问题(没有字段或属性   要求),使用静态类总是更好吗?

我会说,是的。宣布一些事情static你声明了无状态执行的意图(它不是强制性的,而是人们期望的意图)

  

这里有相当多的静态类(比如100)   例如,每个都有一些静态方法会影响   相比之下,执行性能或内存消耗是负面的   具有相同数量的实例类?

不要这么认为,除非你确定静态类真的无法使用,否则会导致很容易搞乱内存分配并导致内存泄漏。

  

当[this]关键字用于调用同一个中的另一个方法时   实例类,实例解析是否仍然发生?

不确定,关于这个点(这是CLR的纯粹实现细节),但是想一想。

答案 2 :(得分:0)

静态方法更快但是OOP更少,如果你将使用设计模式静态方法可能是坏代码,更好地编写业务逻辑而不需要静态,常见的函数如文件读取,WebRequest等更好地实现静态...你的问题没有普遍的答案