web-dev-qa-db-ja.com

静的メソッドとインスタンスメソッドのパフォーマンス

私の質問は、静的メソッドとインスタンスメソッドのパフォーマンス特性、およびそれらのスケーラビリティに関するものです。このシナリオでは、すべてのクラス定義が単一のアセンブリ内にあり、複数の個別のポインタータイプが必要であると想定しています。

考慮してください:

_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. 同じインスタンスクラス内の別のメソッドが呼び出された場合、インスタンスの解決は引き続き発生しますか?たとえば、同じインスタンスの_DoOperation1_内からthis.DoOperation2("abc")のような[this]キーワードを使用します。

101
Bernie White

理論的には、静的メソッドはインスタンスメソッドよりもわずかに優れたパフォーマンスを発揮しますが、他のすべてのものは同等で、余分な隠しthisパラメーターがあるためです。

実際には、これはほとんど違いをもたらさないので、さまざまなコンパイラの決定のノイズに隠れます。 (したがって、2人の人が、一方の人よりも他方の人の方が「証明する」ことができ、結果は一致しません)。特に、thisは通常レジスタで渡され、多くの場合、最初はそのレジスタに含まれているためです。

この最後の点は、理論上、オブジェクトをパラメーターとして受け取り、それを使って何かを行う静的メソッドが、同じオブジェクトのインスタンスとしての同等のものよりも若干劣ることを意味することを意味します。繰り返しますが、その差は非常に小さいため、測定しようとした場合、おそらく他のコンパイラの決定を測定することになります。 (特に、その参照が常にレジスタ内にある場合の可能性も非常に高いため)。

実際のパフォーマンスの違いは、メモリ内にオブジェクトを人工的に取得して自然に静的にする必要があるか、またはオブジェクトの受け渡しのチェーンを複雑に絡めて自然にインスタンスにする必要があるかによって決まります。

したがって、番号1の場合、状態を維持する必要がない場合は、静的であることが常に適切です。これは静的であるためです。コンパイラーの最適化でうまくプレイするという全体的なルールがありますが、パフォーマンスの問題ではありません-誰かが通常の使用を思いつくケースを、奇妙な使用を思いつくケースよりも最適化する努力をした可能性が高いです。

番号2。違いはありません。メタデータの量、実際のDLLまたはEXEファイルに含まれるコードの量、およびそこに含まれるコードの量の両方の観点から、各メンバーのクラスごとに一定量のコストがあります。これはインスタンスでも静的でも同じです。

項目3では、thisthisと同じです。ただし、次の点に注意してください。

  1. thisパラメーターは、特定のレジスターに渡されます。同じクラス内でインスタンスメソッドを呼び出す場合、おそらくそれは既にそのレジスタ内にあります(それが隠されていて、何らかの理由でレジスタが使用されていない限り)。したがって、thisを設定する必要のあるものに設定する必要はありませんに。これは、ある程度まで適用されます。メソッドの最初の2つのパラメーターは、メソッドが行う呼び出しの最初の2つのパラメーターです。

  2. thisがnullでないことは明らかであるため、場合によってはこれを使用して呼び出しを最適化できます。

  3. thisがnullではないことは明らかであるため、メソッド呼び出しを偽装するために生成されたコードは、とにかく必要ないくつかのnullチェックを省略できるため、インライン化されたメソッド呼び出しがより効率的になります。

  4. とはいえ、nullチェックは安価です!

インスタンスメソッドではなく、オブジェクトに作用する一般的な静的メソッドが http://joeduffyblog.com/2011/10/23/on-generics-and-で説明されているコストの一部を削減できることに注意してください。 some-of-the-associated-overheads / 指定されたタイプに対して指定された静的が呼び出されない場合。 「余談ですが、拡張メソッドは、一般的な抽象化をより有料にする優れた方法であることがわかりました。」

ただし、これはメソッドで使用される他の型のインスタンス化にのみ関係し、他の方法では存在しないことに注意してください。そのため、実際には多くのケースに適用されません(他のインスタンスメソッドがそのタイプを使用し、他のコードがそのタイプを使用した)。

概要:

  1. ほとんどの場合、インスタンスと静的のパフォーマンスコストはごくわずかです。
  2. 一般的に、インスタンスに静的に悪用した場合、またはその逆の場合、コストは一般的に発生します。静的とインスタンスの決定の一部にしないと、正しい結果が得られる可能性が高くなります。
  3. 別の型の静的ジェネリックメソッドにより、インスタンスジェネリックメソッドよりも作成される型が少なくなる場合がまれにあります。これにより、時々の利点がわずかになります。めったに使用されないようにします(「まれに」は、呼び出される頻度ではなく、アプリケーションの存続期間に使用される型を指します)。その記事で彼が話していることを理解したら、とにかくほとんどの静的vsインスタンスの決定とは100%無関係であることがわかります。編集:そして、ほとんどの場合、ngenを使用するだけでコストがかかります。

編集:nullチェックがどれだけ安いかについてのメモ(上で主張した)。 .NETのほとんどのnullチェックは、nullをまったくチェックせず、動作するという前提で実行しようとしていたことを続行します。アクセス例外が発生すると、NullReferenceExceptionに変換されます。そのため、C#コードがインスタンスメンバーにアクセスしているために概念的にC#コードがnullチェックを伴う場合、成功した場合のコストは実際にはゼロです。例外はいくつかのインラインコールであり(インスタンスメンバーを呼び出したかのように動作するため)、フィールドにヒットして同じ動作をトリガーするため、非常に安価であり、いずれにしても頻繁に除外される可能性があります(たとえば、メソッドの最初のステップに、フィールドへのアクセスが含まれていた場合)。

141
Jon Hanna

状態を維持する必要がない場合(フィールドやプロパティは不要)、常に静的クラスを使用する方が良いでしょうか?

はい、そうです。何かを宣言するstaticとして、ステートレス実行のintentを宣言します(必須ではありませんが、予想される何かの意図)

これらの静的クラスの数が多い場合(たとえば、それぞれ100の静的メソッドがある場合)、これは、同じ数のインスタンスクラスと比較して、実行パフォーマンスまたはメモリ消費に悪影響を及ぼしますか?

静的クラスが本当にステットレスであることが確実でない限り、そうは思わないでください。そうでない場合は、メモリ割り当てを混乱させてメモリリークを引き起こします。

[this]キーワードを使用して同じインスタンスクラス内の別のメソッドを呼び出す場合、インスタンスの解決は引き続き発生しますか?

this point(これはCLRの純粋な実装の詳細です)についてはわかりませんが、そうだと思います。

7
Tigran

静的メソッドは高速ですが、OOPが少なくなります。デザインパターンを使用する場合、静的メソッドは悪いコードである可能性があります。回答

0
burning_LEGION