c# - 静态方法与实例方法的性能

标签 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 相反。

我的问题是:
  • 当保持状态不是问题时(不需要字段或属性),使用静态类总是更好吗?
  • 如果有大量这些静态类定义(例如 100 个,每个静态方法有多个),与相同数量的实例类定义相比,这是否会对执行性能或内存消耗产生负面影响?
  • 当调用同一个实例类中的另一个方法时,是否仍然发生实例解析?例如使用 [this] 关键字,如 this.DoOperation2("abc")从内部 DoOperation1同一个实例。
  • 最佳答案

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

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

    最后一点意味着,从理论上讲,我们应该期待一个静态方法,它接受一个对象作为参数并用它做一些事情,比作为同一对象上的实例的等效方法稍差。尽管如此,差异是如此微小,以至于如果您试图衡量它,您最终可能会衡量其他一些编译器决策。 (特别是因为该引用始终在寄存器中的可能性也很高)。

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

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

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

    与项目 3, thisthis确实。不过请注意:

  • this参数在特定寄存器中传递。在同一个类中调用实例方法时,它很可能已经在该寄存器中(除非它被隐藏并且由于某种原因使用了该寄存器),因此不需要设置 this 的任何操作。它需要设置为什么。这在一定程度上适用于例如方法的前两个参数是调用的前两个参数。
  • 因为很明显 this不为空,这在某些情况下可用于优化调用。
  • 因为很明显 this不为空,这可能会使内联方法调用再次变得更有效率,因为为伪造方法调用而生成的代码可以省略一些它可能需要的空检查。
  • 也就是说,空检查很便宜!

  • 值得注意的是,作用于对象的通用静态方法,而不是实例方法,可以降低 http://joeduffyblog.com/2011/10/23/on-generics-and-some-of-the-associated-overheads/ 中讨论的一些成本。在没有为给定类型调用给定静态的情况下。正如他所说:“顺便说一句,事实证明,扩展方法是使泛型抽象更具性价比的好方法。”

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

    总结:
  • 大多数情况下,实例与静态的性能成本低于可以忽略不计。
  • 例如,当您滥用静态时,通常会产生什么成本,反之亦然。如果您不将它作为您在静态和实例之间的决定的一部分,您更有可能得到正确的结果。
  • 在极少数情况下,另一种类型中的静态泛型方法会导致创建的类型少于实例泛型方法,这可能会导致 有时 有一个小的好处是很少使用(“很少”是指在应用程序的生命周期中使用的类型,而不是调用它的频率)。一旦你明白了他在那篇文章中谈论的内容,你就会发现它与大多数静态与实例决策 100% 无关。编辑:它主要只有 ngen 的成本,而不是 jitted 代码。

  • 编辑:关于空检查有多便宜的注释(我在上面声称)。 .NET 中的大多数空检查根本不检查空值,而是继续他们将要做的事情,假设它会起作用,如果发生访问异常,它会变成 NullReferenceException .因此,主要是当 C# 代码在概念上涉及空检查时,因为它正在访问实例成员,如果它成功,成本实际上为零。一个异常(exception)是一些内联调用,(因为他们想要表现得好像他们调用了一个实例成员)并且他们只是点击了一个字段来触发相同的行为,所以他们也非常便宜,而且他们仍然经常被排除在外(例如,如果该方法的第一步涉及按原样访问字段)。

    关于c# - 静态方法与实例方法的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12279438/

    相关文章:

    c# - Silverlight 应用程序作为服务提供商

    python - 矢量化 pythonic 方法来获取大于当前元素的元素数

    performance - 带平方根的 while 循环的运行时间/时间复杂度

    php - 在 PHP 的扩展类中使用静态函数

    c# - 解构 EF 对象会导致 Serilog 内存不足

    c# - Monotouch Binding 项目构建错误

    r - 具有共享数据的多个 ggplot2 图表

    java - 如何在单元测试环境中使用抛出异常的 PowerMock 来模拟 Java 静态类初始化器

    php从同一个类中的静态方法调用类方法但未实例化

    c# - ListView 控件呈现问题与组、复选框和 View 模式 SmallIcon