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

Ber*_*ite 103 c# performance il static-methods

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

考虑:

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.
}
Run Code Online (Sandbox Code Playgroud)

上述类表示辅助样式模式.

在实例类中,解析实例方法需要花费一些时间来与StaticClass相反.

我的问题是:

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

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

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

Jon*_*nna 142

从理论上讲,静态方法应该比实例方法稍好一些,所有其他条件相同,因为额外的隐藏this参数.

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

最后一点意味着理论上,我们应该期望一个静态方法,它将一个对象作为一个参数,并用它做一些事情,比同等对象上的一个实例稍微好一些.但是,差异非常小,如果你试图测量它,你可能最终会测量其他一些编译器的决定.(特别是因为该参考在整个时间内在寄存器中的可能性也非常高).

真正的性能差异将归结为你是否人为地在内存中获取对象来做一些自然是静态的事情,或者你是以复杂的方式纠缠对象传递链以做自然应该实例化的事情.

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

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

与第3项一样,this也是this如此.但请注意:

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

  2. 由于它很明显this不为空,因此在某些情况下可以用来优化调用.

  3. 由于很明显它this不是null,这可能会使内联方法调用再次更有效,因为伪造方法调用所产生的代码可以省略它可能需要的一些空值检查.

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

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

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

摘要:

  1. 大多数情况下,实例与静态的性能成本低于可忽略不计.
  2. 例如,滥用静态的地方通常会产生什么成本,反之亦然.如果您没有在静态和实例之间做出决定,那么您更有可能获得正确的结果.
  3. 在极少数情况下,另一种类型的静态泛型方法导致创建的类型少于实例泛型方法,这使得它有时可以很少使用很少使用(并且"很少"指的是它在其中使用的类型.应用程序的生命周期,而不是它的调用频率).一旦你在那篇文章中得到他正在谈论的内容,你就会发现它与大多数静态vs实例决策无关.编辑:它主要只有ngen的成本,而不是jitted代码.

编辑:关于如何便宜的空检查的说明(我在上面声称)..NET中的大多数空值检查根本不检查空值,而是继续它们将要做的假设它将起作用,并且如果发生访问异常,它将变为NullReferenceException.因此,大多数情况下,从概念上讲,C#代码涉及进行空检查,因为它正在访问实例成员,如果成功则成本实际为零.一个例外是一些内联调用,(因为他们希望表现得好像他们调用了一个实例成员)并且他们只是按一个字段来触发相同的行为,因此它们也非常便宜,但它们仍然经常被遗漏(例如,如果方法的第一步涉及访问字段).

  • 很好的答案,感谢仿制药信息. (4认同)

Tig*_*ran 7

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

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

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

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

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

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