小编典典

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

c#

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

考虑:

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")从内DoOperation1相同的实例的。


阅读 746

收藏
2020-05-19

共1个答案

小编典典

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

实际上,这几乎没有什么区别,以致于它会被各种编译器决策所掩盖。(因此,两个人可以“证明”一个人比另一个人更好,但结果不一致)。尤其重要的this是,通常在寄存器中传递,并且通常从该寄存器开始。

最后一点意味着,从理论上讲,我们应该期待一个静态方法,该方法将一个对象作为参数并对其执行某些操作,其效果比该对象作为实例的等效方法稍差。同样,差异很小,以至于如果尝试对其进行度量,最终可能会评估其他一些编译器决策。(特别是因为该引用始终在寄存器中的可能性也很高)。

真正的性能差异将归结为您是人为地将对象存储在内存中以执行应该自然是静态的操作,还是以复杂的方式缠结对象传递链来执行自然应为实例的操作。

因此,对于数字1。当不关心保持状态时,最好总是保持静态, 因为这就是static的含义 。这不是性能问题,尽管总的原则是要很好地进行编译器优化-
比起那些有奇怪用法的人,更有可能有人努力优化了有常规用法的案例。

2号。没有区别。对于每个成员来说,每类都有一定数量的成本,这取决于元数据的数量,实际DLL或EXE文件中的代码量以及实际的代码量。无论是实例还是静态,这都是相同的。

随着第3项,thisthis做。但是请注意:

  1. this参数在一个特定的寄存器传递。当在同一类中调用实例方法时,它很可能已经在该寄存器中(除非由于某种原因它被隐藏并使用了该寄存器),因此无需采取任何操作this即可将设置为需要设置的值。这在某种程度上适用于例如方法的前两个参数,该方法是它进行的调用的前两个参数。

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

  3. 既然很明显this不为null,这可能会使内联方法调用更加有效,因为为伪造该方法调用而生成的代码可以省略一些可能仍然需要的空检查。

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

值得注意的是,作用在对象上的通用静态方法(而不是实例方法)可以减少http://joeduffyblog.com/2011/10/23/on-
generics-and-some-of-在没有为给定类型调用给定静态变量的情况下,the-associated-heads
/
。正如他所说:“顺便说一句,事实证明,扩展方法是使泛型抽象更加按需付费的好方法。”

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

摘要:

  1. 通常情况下,实例与静态的性能成本可以忽略不计。
  2. 例如,如果您滥用静电,反之亦然,通常会有什么成本。如果您不将其作为静态和实例之间决策的一部分,则更有可能获得正确的结果。
  3. 在极少数情况下,另一种类型的静态泛型方法导致创建的类型少于实例泛型方法,这 有时 会使它变得很少使用(很少使用)(而“很少”指的是在应用程序的生命周期,而不是调用频率)。一旦您了解了他在该文章中所讨论的内容,您就会发现它与大多数static-vs-instance决策都是100%不相关的。编辑:而且它大多数只用ngen花费,而不用jitted代码。

编辑:关于便宜的空值检查的注释(我在上面声明过)。.NET中的大多数null检查根本不检查null,而是在假设它可以工作的情况下继续执行它们要做什么,并且如果发生访问异常,它将变成NullReferenceException。这样,大多数情况下,当C#代码在概念上涉及空检查(因为它正在访问实例成员)时,如果成功,则成本实际上为零。某些内联调用是一个例外,(因为它们希望表现得像调用实例成员一样),并且它们只是命中字段以触发相同的行为,因此它们也很便宜,而且无论如何仍然经常被忽略。
(例如,如果方法的第一步涉及按原样访问字段)。

2020-05-19