web-dev-qa-db-ja.com

静的メソッドはより効率的ですか?

メモリと時間の観点から、メソッドを静的にする方が良いですか?

47
Yaron Naveh

通常はそうです、「this」参照を渡す必要はありません。その参照はECXレジスタに渡されるため、追加のスタックスペースは必要ありません。同じクラスのインスタンスメソッドから呼び出しを行う場合、レジスタはすでに設定されているため、節約はまったくありません。ただし、メソッドが別のクラスにある場合、x86 CPUコアへのプレッシャーを軽減するのに役立ちます。x86には、多くのレジスタがありません。測定可能なパフォーマンスの改善が見られることは非常にまれです。

私は、インスタンスメンバーを静的として使用しないクラスのメソッドを宗教的にマークします。 staticキーワードによって提供される固有のコントラクトを評価します:「このメソッドはオブジェクトの状態を変更しません」。

86
Hans Passant

メソッドが含まれているクラスからの状態情報を必要としない場合は、メソッドを静的にする必要があります。

ポリモーフィズムを気にしない場合は、クラスインスタンスメンバーを取得してに渡すかどうかを決定するだけで、インスタンスまたは静的のいずれかのメソッドを記述できます。引数としてのメソッド。 考慮すべきことは、構文が自然であるかどうか、コードが理解しやすく意味があるかどうかなどです。

インスタンスと静的メソッドのパフォーマンスオーバーヘッドはごくわずかであるため、このレベルでの最適化について心配する必要はありません。はい、タイプのディスパッチテーブルで使用されるスペースがあります(メソッドが仮想の場合)-しかし、それは小さな一定のオーバーヘッドです。はい、インスタンスメソッドと静的メソッドの呼び出しにはわずかなオーバーヘッドもありますが、やはり小さなオーバーヘッドです。

これは、マイクロ最適化のレベルのように思われます。実際にプログラムのパフォーマンスに影響を与えていると信じる測定可能で具体的な証拠がない限り、避ける必要があります。実際、間違ったことをすると、タイプの非表示のthis参照を介してアクセスするのではなく、追加のパラメーターを渡す(スタックにコピーするなど)コストが発生する可能性がありますパフォーマンスが悪い

メソッドのセマンティクスを分析し、それに基づいて静的/インスタンスの決定を行う方が適切です。

53
LBushkin

とにかくインスタンスを渡す場合(SomeStaticMethod(obj, "abc", 123);)、実際にはそうではありません。ポリモーフィズムのないシナリオでのみ静的メソッドを有効に使用できます。そのような場合、プロパティなどの単純なものがインライン化されている可能性が高くなります。とにかく。

オブジェクトを「自然に」使用する(obj.SomeMethod("abc",123);)-コードを単純に保ち、profileパフォーマンスの問題を見つけるvery違いが生じる可能性は低いいくつかのveryタイトなループを実行していない限り、インスタンスと静的の間。それが問題になるかもしれないいくつかのシナリオがありますが、それらはかなり専門的です。

9
Marc Gravell

静的メソッドと非仮想インスタンスメソッドの間にほとんどまたはまったく違いはありません。後者は、「隠された」引数としてthis prointer/referenceを持っています。生成されたマシンコードでは、両方の種類の呼び出しは非常によく似ています。

メソッドがオブジェクトに依存/変更しない場合、メソッドは静的である必要があります。

一方、仮想メソッド(オーバーライド可能)では、呼び出し元がいわゆる vtable で正確な実装を検索する必要があります。コンパイラーが非常に小さなメソッドをインライン化するのを防ぐことに加えて(単純なプロパティアクセサーは非常に頻繁にインライン化されます)、ルックアップには数サイクルかかります。

それでも、仮想メソッドは、C#/ CLRで利用できる最速の動的ディスパッチです。デリゲートやリフレクションよりもはるかに高速です。

5

この種の質問はたくさんあります。静的メソッドは速い/遅いですか?仮想関数は高速/低速ですか? i ++は++ iよりも速い/遅いですか? for(;;)はwhile(true)よりも速い/遅いですか?

いくつかのソフトウェアを手に入れることは価値があり、 それを調整する 。これにより、実際にソフトウェアのパフォーマンスに実際に影響を与える種類のことをよく理解できます。

そうすれば、そのような質問への答えは(ほとんどの場合)それが重要ではないことがわかります。

一般化できれば、私の経験では、ソフトウェアを遅くするのは、無害に見えるが、その時間の消費が想像よりも桁違いに大きいコード行の使用です。それらは無実に見えるため、コードを見ても確実に見つけることはできません。例:大きなデータ構造が存在することを確認するためだけに、大きなデータ構造の割り当て、初期化、および割り当て解除を繰り返します。する必要のない文字列を国際化する。プロパティの単純な設定を、大規模なデータ構造全体でメソッド呼び出しの大規模なカスケードに変えることができる通知スタイルのプログラミング。 nが大きくなることを除いて問題になることのない単純なO(n ^ 2)操作。 (a <b)は、aとbがintであろうと大きなクラスであろうと、ほぼ同じ時間かかると考えます。この「無実に見えることによる時間の掛け算」は、抽象化の複数の層に複合効果をもたらすため、私の経験では、大規模なソフトウェアはそれでいっぱいになる傾向があります。

3
Mike Dunlavey

ほとんどの場合、違いはごくわずかですが、静的な方が効率的です。

静的メソッド呼び出しでは、次の手順は回避されます。

  1. オブジェクト参照(this)がnullでないことを確認します。
  2. 仮想ディスパッチテーブルで正しいメソッドを見つける。
  3. オブジェクト参照をスタックに配置します。
1

特定のクラス内で作成する多くのユーティリティメソッドは、クラス内の少数のデータメンバーのみを必要とするか、まったく必要ないことがわかりました。このような場合、私はそれらのメソッドを(スタンドアロンの)静的メソッドとして記述し、必要ないくつかのデータ項目を直接渡す傾向があります。

それらが特に一般的で、他のクラスにとって十分に役立つ場合は、それらを公開することもできます。

0
David R Tribble