2012-01-08 7 views
7

私はもともとネイティブのC++プログラマであり、C++ではプログラム内のすべてのプロセスがコードにバインドされています。つまり、実行しない限り何も起こりません。そして、あなたが書いたことに従って、メモリのすべてのビットが割り当てられ(割り当てが解除されます)。だから、パフォーマンスはすべてあなたの責任であり、良いことをすれば素晴らしいパフォーマンスが得られます。マネージコードでは、パフォーマンスを維持するために何を見なければなりませんか?

(注:STLのように自分自身で書いていないコードについては不平を言わないでください。結局のところ、C++のアンマネージコードであり、それは重要な部分です)。

JavaやC#のコードなどの管理コードでは、すべてのプロセスを制御するわけではなく、メモリはある程度隠されているか、管理されていません。そしてそれはパフォーマンスを比較的未知にし、ほとんどあなたは悪いパフォーマンスを恐れる。

私の質問は次のとおりです。マネージコードで優れたパフォーマンスを達成するには、どのような問題や太字線を覚えておく必要がありますか?

私だけのようないくつかの実践を考えることができます:

  • はボクシングとアンボクシングの意識して。
  • あなたのニーズに最も適し、最も低い運用コストを持つ正しいコレクションを選択してください。

しかし、これらは決して十分ではなく、説得力のあるものではありません。実際にはおそらく私はそれらを言及すべきではありませんでした。

私はC++ VS C#(またはJava)コードを比較することを求めていません。問題を説明するためにC++を説明しました。

答えて

5

ここには1つの答えはありません。これに答える唯一の方法は、プロフィールです。早く、頻繁に測定する。ボトルネックは、通常、あなたが期待する場所ではありません。 を実際にに傷つけるように最適化します。これにはmvc-mini-profilerを使用していますが、同様のツールであれば動作します。

あなたはGCに焦点を当てているようです。現在、が問題になることがありますが、通常は特定のケースでのみ発生します。大部分のシステムでは、世代別GCが優れています。

明らかに外部リソースは遅くなります。キャッシュが重要な場合があります。非常に長寿命のデータがある奇妙なシナリオでは、長いGEN-2収集を避けるために構造体で行うことができるトリックがあります。あなたが測定するまでを知ることができません - あなたは、シリアル化(ファイル、ネットワークなど)、マテリアライゼーション(ORM)、または単にコレクション/アルゴリズムの選択の悪さが最大の問題かもしれません。しかし


2つのこと:

  • あなたがIDisposableインターと「使用」は
  • は、ループ内の文字列を連結していない何を意味するかを理解しておいてください。大量連結はStringBuilderの仕事です
0

私はより良い理解をお勧めしますgarbage collectionアルゴリズム。あなたはそのことに関する良い本を見つけることができます。 The Garbage Collection Handbook(Richard Jones、Antony Hosking、Eliot Mossによる)。

あなたの質問は実際には特定の実装に関連しており、おそらく特定の実装にも関連しています。たとえばMonoBoehm'sガーベッジコレクタを使用するために(たとえばバージョン2.4では)使用されましたが、現在は世代別コピーを使用しています。

いくつかのGC手法が非常に効率的であることを忘れないでください。 A.Appelの古い論文Garbage Collection can be faster than stack allocationを思い出してください(しかし、今日、キャッシュのパフォーマンスははるかに重要なので詳細は異なります)。

ボクシング(& unboxing)と配分を意識していると思います。いくつかのコンパイラでは、これらを最適化することができます(一部を避けて)。

GCのパフォーマンスが大きく異なる可能性があることを忘れないでください。あなたのアプリケーションには良いGCがあり、悪いものはあります。

一部のGC実装はかなり高速です。たとえばその中にはOcaml

私はあまり気にしません。早すぎる最適化は悪です。

(スマートポインタでもref-countersであってもC++メモリ管理は貧弱な人のガーベッジコレクション手法と見なすことができ、C++が何をしているのか完全に制御することはできません。オペレーティングシステム固有のシステムコールを使用して::operator newを実装してください。

1

管理対象言語のパフォーマンスには、実行時に構造が変更される可能性があります。よりよく最適化される。

例えばJVMほとんどの人が使うデフォルトは、それがネイティブコードにプログラムの一部を変換して実行して、実際にその場ででライニング、あなたのコードを最適化するであろう日のHotspot VMであり、そのようなCLRなどの他の最適化(または他のマネージドランタイム)は、C++を使用することはありません。 さらにホットスポットは、コードのどの部分が最も使用されているかを検出し、それに応じて最適化します。 管理対象システムのパフォーマンスを最適化することは、介入なしでコードを高速化できる中間層を使用しているため、管理されていないシステムよりも若干難しいことがわかります。

私はここでpremature optimizationの法律を呼び出し、パフォーマンスが問題になる場合は最初に正しい解決策を作成して、最適化を試みる前に実際に何が遅いかを測定する必要があると言います。

+0

常にJITはすべてをネイティブコードにコンパイルします。私はそれが投機的なインライン化や再コンパイルをしないと思っています。 –

+0

@BenVoigt [この回答](http://stackoverflow.com/questions/4043821/performance-differences-between-debug-and-release-builds/4045073#4045073).NET JITコンパイラはいくつかのメソッドのライニングを含む最適化。私が作ったのは、管理された言語が、実行時に適応的に、または使用時に、そのような最適化を実行する能力を提供するということです。 – ahjmorton

+0

ターゲットを静的に決定できる場合、インライン展開します。投機的なインライン展開は、Hotspotが行うより高度な技術であり、.NETではそうではありません。 –

4

大きなオブジェクトを再利用することは私の経験上非常に重要です。

ラージオブジェクトヒープ上のオブジェクトは暗黙的に第2世代であるため、完全なGCでクリーンアップする必要があります。それは高価です。

+0

+1、これは「オブジェクトプーリング」と呼ばれます:) – MattDavey

+1

これは、(おそらくほとんどの)実装では当てはまります。それは実装の詳細ですが、重要なものです。 –

+0

@BasileStarynkevitchこれは本当です。非世代のGCのオブジェクトプーリングは、実際に**パフォーマンスを低下させる可能性があります**! – MattDavey

0

.NETジェネリックスは参照タイプに特化していないため、インライン化がどれほどできるか​​が厳しく制限されています。特定のパフォーマンスのホットスポットでは、より最適化される特定の実装を優先してジェネリックコンテナタイプを守ることができます。 (注:これは要素タイプがobjectの.NET 1.xコンテナを使用することを意味しません)。

-1

あなたは:大きなオブジェクトを使用して 私の経験では非常に重要です。

ラージオブジェクトヒープ上のオブジェクトは暗黙的に第2世代であるため、完全なGCでクリーンアップする必要があります。それは高価です。

関連する問題