[解決済み] C++のクラスで仮想メソッドを持つことのパフォーマンスコストは?
質問
C++のクラス(またはその親クラス)に少なくとも1つの仮想メソッドがあることは、そのクラスが仮想テーブルを持ち、すべてのインスタンスが仮想ポインタを持つことを意味します。
ですから、メモリ コストは非常に明確です。 最も重要なのはインスタンスのメモリ コストです (特にインスタンスが小さい場合、たとえば整数を含むだけの場合、この場合、すべてのインスタンスに仮想ポインタを持つと、インスタンスのサイズが 2 倍になる可能性があります)。 仮想テーブルによって使用されるメモリ領域については、実際のメソッドコードによって使用される領域と比較して、通常は無視できるものだと思います。
ここで私の疑問が生じます。メソッドを仮想化するための測定可能なパフォーマンス コスト (すなわち、速度への影響) はあるのでしょうか。 実行時に、すべてのメソッド呼び出し時に仮想テーブルを検索するので、このメソッドへの呼び出しが非常に頻繁で、このメソッドが非常に短い場合、測定可能なパフォーマンスのヒットがある可能性がありますか? プラットフォームに依存すると思いますが、どなたかベンチマークを実行されたことはありますか?
私が質問している理由は、プログラマーがメソッドの仮想定義を忘れたことによるバグに遭遇したことです。 この種のミスを見るのは初めてではありません。 そして、私は考えました:なぜ、私たちは を追加する必要があるのでしょうか。 の代わりに、必要なときに仮想キーワードを を削除します。 であることが確実な場合に、仮想キーワードを削除します。 ではなく は必要ないのでしょうか? もしパフォーマンスコストが低いのであれば、私のチームでは単純に以下のように推奨すると思います:単純に ごとに メソッドをデフォルトで仮想化し、デストラクタも含め、すべてのクラスで仮想化し、必要なときだけ削除することです。 それはあなたにとってクレイジーに聞こえますか?
どのように解決するのか?
I タイムを計測しました を 3ghz のインオーダーの PowerPC プロセッサで実行しました。そのアーキテクチャでは、仮想関数呼び出しは直接 (非仮想) 関数呼び出しよりも 7 ナノ秒長くかかります。
したがって、関数が些細な Get()/Set() アクセッサのようなものでない限り、コストについて心配する価値はあまりなく、インライン以外のものは無駄のようなものです。0.5ns にインライン化された関数の 7ns のオーバーヘッドは深刻ですが、実行に 500ms かかる関数の 7ns のオーバーヘッドは無意味なものです。
仮想関数の大きなコストは、vtable内の関数ポインタのルックアップ(これは通常1サイクル)ではなく、間接ジャンプが通常ブランチ予測できないことです。間接ジャンプ(関数ポインタを介した呼び出し)が終了し、新しい命令ポインタが計算されるまで、プロセッサは命令をフェッチできないため、大きなパイプラインバブルが発生する可能性があります。つまり、仮想関数呼び出しのコストは、アセンブリを見ただけではわからないほど大きいのです...しかし、それでもわずか7ナノ秒なのです。
編集してください。 Andrew, Not Sure, and others raise the very good point that a virtual function call may cause an instruction cache miss: if you jump to a code address that is not in cache, then the whole program comes to a dead halt while the instructions are fetched from main memory. これは 常に であり、Xenon では約 650 サイクル (私のテストによる) の大幅なストールです。
しかし、これは仮想関数に固有の問題ではありません。なぜなら、直接の関数呼び出しでさえ、キャッシュにない命令にジャンプするとミスが発生するからです。重要なのは、関数が最近実行されたかどうか (キャッシュにある可能性が高くなる)、そして、アーキテクチャが静的分岐 (仮想分岐ではない) を予測し、それらの命令を前もってキャッシュにフェッチできるかどうかということです。私の PPC はそうではありませんが、おそらく Intel の最新のハードウェアはそうでしょう。
私のタイミングは、実行におけるキャッシュミスの影響を制御し (私は CPU パイプラインを分離して調査しようとしていたので、意図的に)、そのコストを割り引いています。
関連
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] 抽象メソッドと仮想メソッドの違いは何ですか?
-
[解決済み] Dockerコンテナのランタイムパフォーマンスコストとは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】coutはstdのメンバではない
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】C++エラー:の初期化に一致するコンストラクタがありません。
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件
-
[解決済み] キャッシュフレンドリーコードとは何ですか?