C vs.メモリ割り当てのパフォーマンスのための C++
-
22-09-2019 - |
質問
複雑な問題をモンテカルロ解析するために C 言語で書かれたコードの開発に参加する予定です。このコードは、パフォーマンスを高速化するためにメモリ内に巨大なデータ配列を割り当てます。そのため、コードの作成者は、C を使用すると、(メモリ リークに関して) より高速で信頼性の高いコードを作成できると主張して、C++ ではなく C を選択しました。
それに同意しますか?計算中に 4 ~ 16 GB のデータ配列をメモリに保存する必要がある場合、何を選択しますか?
解決
間違いなくC++です。デフォルトでは、この 2 つに大きな違いはありません。 しかし C++ には、C にはないいくつかの機能があります。
- コンストラクター/デストラクター。これらにより、ほとんどのメモリ管理が自動化され、信頼性が向上します。
- クラスごとのアロケータ。これらにより、特定のオブジェクトの設計方法や使用方法に基づいて割り当てを最適化できます。これは、(わかりやすい例として) 多数の小さなオブジェクトが必要な場合に特に便利です。
肝心なのは、この点において、C が C++ よりも優れている可能性はまったくないということです。最悪の場合、全く同じことを同じ方法で行うことができます。
他のヒント
C ++とそのからの不在は、潜在的に重い大量の演算コードの大幅なスピードの向上を与え、それがキーワードrestrict
あるとC99の一つの特徴があります。あなたがサポートしているC ++コンパイラを使用することができます場合は、最適化に来るとき、それは、あなたはキット内の余分なツールを持っています。十分なインライン化がrestrict
、よりと同じ最適化を許可することができます。これは、しかし、唯一の潜在的な利益です。また、メモリの割り当てとは何の関係もありません。
コードの作者は4〜16ギガバイトの配列を割り当てるCおよびC ++コードの性能差を示すことができた場合は、()私は驚いたんだけど、OK、違いがありますし、(b)はどのように多くの回のプログラムは、このような大きな配列を割り当てるために起こっていますか?あなたのプログラムは、実際にメモリを割り当てるのにかなりの時間を過ごすために起こっている、またはそれはその時、のアクセスのメモリの大半を過ごし、計算をしているのですか?それは実際に長い時間がかかります。の行うのそれは割り当てるために要した時間と比較して4GBの配列と、あなたは「何でも」のパフォーマンスを心配する必要があることを意味し、いない割り当ての性能を持つもの。彼らは、ブロックを降りるどのように迅速スプリンターズは多くのことを気に。マラソンランナー、そんなにます。
また、どのようにベンチマーク注意する必要があります。あなたはmalloc(size)
に対する例new char[size]
のために比較されなければなりません。あなたはmalloc(size)
に対してnew char[size]()
をテストする場合、それは後者のセット以来、不当な比較0にメモリだと前者はしません。代わりにcalloc
と比較するだけでなく、そのmalloc
とcalloc
に注意し、彼らが測定可能速く証明しないと(そう)イベントの両方でC ++から利用可能です。
最終的に、著者は「所有」またはプロジェクトを開始し、むしろC ++よりもCに書き込みを好むならば、彼はおそらく、スプリアス性能の主張とその決定を正当化してはならない、けれども、彼は "と言って、それを正当化する必要があります私はCを好む、それは「私が使用しているものです。誰かが、言語のパフォーマンスについては、このような主張を行い、それが真実ではないことがテストで判明したときに通常、あなたはパフォーマンスが言語設定のための本当の理由ではないことを発見します。請求虚偽を証明することは、実際に突然C ++を好き起動するには、このプロジェクトの作者が発生することはありません。
メモリ割り当ての観点からCとC ++の間には実質的な違いはありません。あなたは、オブジェクト上の仮想メソッドを持っていることを選択した場合はC ++は、仮想ポインタとしてより「隠された」データを持っているというように。しかし、文字の配列を割り当てることは、C ++のようにCにだけ高価なようで、実際に、彼らはおそらく、両方のそれを行うにはmalloc関数を使用しています。性能の面では、C ++は、アレイ内の各オブジェクトのコンストラクタを呼び出します。これは、デフォルトのコンストラクタが何もしないし、離れて最適化され、存在する場合に行われることに注意してください。
は限り、あなたはメモリの断片化を避けるために、データのプールを事前に割り当てるしているとして、あなたはどこへ行くか良いことがあります。あなたは仮想メソッドのない単純なPOD-構造体を持ち、およびコンストラクタなしで、有意差がない場合ます。
の C ++の冷遇で唯一のものは、それが更なる複雑のですです。 C ++の機能なしでC ++コンパイラを使用すると、同じパフォーマンスを提供します。 C ++を使用して、正しく、あなたがより速くなるためにいくつかのposisbilitiesを持っています。
の言語はあなたの問題ではありません、大きな配列を割り当て、横断することです。
(のいずれかの言語で)あなたが配分に作ることができる主な致命的なミスが唯一の実際の値以降で、それを埋めるために、それをゼロに初期化し、メモリの16Gを割り当てるされます。
私は参照の局所性を向上させるアルゴリズムの最適化に期待する最もパフォーマンスの向上。
基盤となるOSによっては、キャッシングアルゴリズムをも影響を及ぼす可能性 - 例えばmemroyの範囲のみが順次処理されていることを示す。
生データを割り当てる場合、通常は両方とも同じランタイム ライブラリ メカニズムを使用するため、ほとんどのシステムでは C と C++ に違いはありません。これは、C++ でのコンストラクター呼び出しのランタイムも測定し、C でのあらゆる種類の初期化コードのランタイムを含めることを都合よく忘れていたという、典型的なベンチマークの落とし穴だったのではないでしょうか。
また、C++ で RAII を使用している場合は (当然のことですが)、「(メモリ リークに関して) より信頼性が高い」という議論は根拠がありません。誰かがリークの確実性を高めることに言及していない限り、RAII、スマート ポインター、コンテナー クラスを使用すると、リークの可能性は増加するのではなく、減少します。
これほど多くのメモリを割り当てることに関する私の主な懸念は 2 つあります。
- モンテカルロ シミュレーションを実行しているマシンの物理メモリの制限に近づいている場合、仮想メモリ システムが大量のページングを開始する必要があるときにディスクがスラッシングを開始する可能性があるため、これはパフォーマンスを低下させる良い方法です。 。多くの人がそう思っていますが、仮想メモリは「無料」ではありません。
- プロセッサ キャッシュの使用量を最大化するには、データ レイアウトを慎重に検討する必要があります。そうしないと、そもそもデータをメイン メモリに保持する利点が部分的に失われます。
、私はより高速の割り当てのために言語を変更しない、再設計、むしろお勧めします。一度メモリを割り当て、その後、計算の多くを実行する場合、私はそれらの計算がボトルネックになることを期待します。割り当てのコストが重要である場合は、何かが間違ってここにある。
あなたも、C ++でメモリ割り当て関数のCファミリを使用することができます。標準malloc
とfree
両方、realloc
をスタック上にメモリを割り当てるために、アレイおよびalloca
をshring /拡大
new
で行く場合は、、それは(主にデバッグ時)に必要とされるよりも多くのメモリを割り当てると一貫性のための余分なチェックを行います。また、クラスのコンストラクタを呼び出します。リリース(-O3
)の差は、ほとんどのアプリケーションで無視することができるであろう築くます。
今、何new
は、malloc関数はインプレースnew
でないことをもたらします。あなたはこのようにそれ瞬時ます。
new
を使用することができます
はすべてがすべてで、私があるため、パフォーマンス上の問題のCから離れません。クラスはCと同等のように、レジスタの代わりに、パラメータにthis
ポインタを渡すのでどちらかといえば、あなたのコードは、より効率的になります。 Cから離れて滞在する本当の理由は、C ++ランタイムのサイズです。あなたは組み込みシステムまたはブート・ロードされたプログラムのためのプログラムを開発する場合、あなたは〜4MBのランタイムを埋め込むことはできません。しかし、通常のアプリケーションでは、これは違いをすることはありません。
計算中に 4 ~ 16 GB のデータ配列をメモリに保存する必要があり、マシンの物理メモリが 2 GB しかない場合はどうすればよいでしょうか?
マシンに 16GB の物理メモリがある場合はどうなるでしょうか?オペレーティング システムは物理メモリを消費しませんか?
オペレーティング システムでは 4GB、16GB などのアドレス空間も許可されていますか?
パフォーマンスが実装上の主要な制約である場合、同一の環境とアルゴリズムを前提とした C と C++ の間の測定可能なパフォーマンスの違いの問題よりも、使用することを目的としたプラットフォームがどのように機能し、実行されるかを理解することの方がはるかに重要であると私は提案します。