私の理解では、C/C++は特定のマシンアーキテクチャで実行するネイティブコードを生成します。逆に、JavaやC#などの言語は、ネイティブアーキテクチャを抽象化する仮想マシン上で実行されます。論理的には、この中間ステップのためにJavaまたはC#がC++の速度に一致することは不可能に思えますが、最新のコンパイラ(「ホットスポット」)はこの速度に達するか、それを超えることさえあると言われていますそれ。
おそらくこれは言語の質問よりもコンパイラーの質問の方が多いかもしれませんが、これらの仮想マシン言語の1つがネイティブ言語よりも優れたパフォーマンスを発揮する方法を英語で説明できますか?
一般的に、C#とJavaは、JITコンパイラー(最初に実行されたときにILをコンパイルするコンパイラー)がC++コンパイル済みプログラムが照会できないため最適化できないので、同じくらい高速または高速になります。この機械。マシンがIntelかAMDかを判断できます。 Pentium 4、Core Solo、またはCore Duo。または、SSE4などをサポートする場合.
C++プログラムは、すべてのマシンで適切に動作するように、通常は混合最適化で事前にコンパイルする必要がありますが、単一の構成(つまり、プロセッサ、命令セット、その他のハードウェア)ほど最適化されていません。
さらに、特定の言語機能により、C#およびJavaのコンパイラーは、C/C++コンパイラーでは安全ではない特定の部分を最適化できるようにコードに関する仮定を行うことができます。ポインターにアクセスできる場合、多くの最適化が安全ではありません。
また、JavaとC#は、ガベージコレクタとコード間の抽象化層により、すべてのヒープ圧縮を一度に実行できるため(かなり高価な操作)、C++よりも効率的にヒープ割り当てを行うことができます。
この次のポイントでJavaについて話すことはできませんが、たとえばC#は、メソッドの本体が空であることを知っている場合、実際にメソッドとメソッド呼び出しを削除することを知っています。そして、コード全体でこの種のロジックを使用します。
ご覧のとおり、特定のC#またはJava実装が高速になる理由はたくさんあります。
これですべて、C++でできること、特にグラフィックス領域で、そしてハードウェアに近づいたときは何でも吹き飛ばす特定の最適化をC++で行うことができます。ポインタはここで不思議に思います。
あなたが書いているものに応じて、私はどちらか一方と一緒に行くでしょう。ただし、ハードウェアに依存しないもの(ドライバー、ビデオゲームなど)を作成している場合、C#のパフォーマンスについては心配しません(Javaについて話すことはできません)。それはうまくいくでしょう。
Java側の1つ @ Swati は、良い記事を指摘しています。
前の投稿ですでに述べたように、JITは実行時にIL /バイトコードをネイティブコードにコンパイルできます。そのコストは言及されましたが、その結論には言及されませんでした。
JITには、すべてをコンパイルできないという大きな問題が1つあります。JITのコンパイルには時間がかかるため、JITはコードの一部のみをコンパイルしますが、静的コンパイラーは完全なネイティブバイナリを生成します。コンパイラは単純にJITを簡単に上回るでしょう。
もちろん、C#(またはJava、またはVB)は通常、C++よりも実行可能で堅牢なソリューションを作成するのに高速です(C++に複雑なセマンティクスがあり、C++標準ライブラリが面白くて強力であるにもかかわらず、フルと比較するとかなり貧弱です) .NETまたはJavaの標準ライブラリの範囲)、したがって、通常、C++と.NETまたはJava JITの違いはほとんどのユーザーには表示されません。重要なバイナリについては、 C#またはJavaからC++処理を呼び出すことができます(この種のネイティブ呼び出しはそれ自体で非常にコストがかかる場合もあります)...
通常、C++ランタイムコードをC#またはJavaの同等のコードと比較していることに注意してください。しかし、C++には、そのままJava/C#より優れた機能が1つあります。それはテンプレートメタプログラミングです。コード処理はコンパイル時に行われ(したがって、コンパイル時間が大幅に増加します)、実行時間はゼロ(またはほぼゼロ)になります。
私はまだこれで実際の効果を見ています(概念だけで遊んでいますが、その時までに違いはJITの実行の秒でした、そしてzeroC++の場合)、しかし、これは言及する価値があります。事実、テンプレートのメタプログラミングは簡単ではありません...
2011-06-10の編集: C++では、型の再生はコンパイル時に行われます。つまり、非汎用コードを呼び出す汎用コードを生成します(たとえば、文字列から型Tへの汎用パーサー、認識される型Tの標準ライブラリAPIの呼び出し、そのユーザー)は非常に簡単で非常に効率的ですが、JavaまたはC#の同等の記述はせいぜい苦痛であり、コンパイル時に型がわかっていても実行時に常に遅くなり、解決されますあなただけ 希望 jITがすべてをインライン化するためのものです。
...
2011-09-20を編集: Blitz ++の背後にあるチーム( Homepage 、 Wikipedia )はそのように進み、どうやら彼らの目標は、ランタイムの実行から可能な限り移動することにより、科学計算におけるFORTRANのパフォーマンスに到達することですコンパイル時間、C++テンプレートメタプログラミング経由。だから、私はまだこれに実際の人生の影響を見ています"どうやら上で書いた部分 する 実生活に存在します。
C++のメモリ使用量はJava/C#とは異なるため、異なる利点/欠点があります。
JITの最適化に関係なく、メモリへの直接ポインタアクセスほど高速なものはありません(プロセッサキャッシュなどをしばらく無視しましょう)。したがって、メモリ内に連続したデータがある場合、C++ポインター(つまり、Cポインター... Caesarに期限を設定しましょう)を介してアクセスすると、Java/C#の場合よりも何倍も速くなります。また、C++にはRAIIがあります。RAIIを使用すると、C#やJavaよりもはるかに簡単に処理できます。 C++は、オブジェクトの存在をスコープするためにusing
を必要としません。また、C++にはfinally
句がありません。これはエラーではありません。
:-)
また、C#プリミティブに似た構造体にもかかわらず、C++の「スタック」オブジェクトは、割り当てと破棄に費用がかかりません。また、クリーニングを行うために独立したスレッドで動作するGCは必要ありません。
メモリの断片化に関しては、2008年のメモリアロケータは、通常はGCと比較される1980年の古いメモリアロケータではありません。断片化が発生しない場合のデフラグ?適切なタスクに適切なアロケーターを使用することは、C++開発者ツールキットの一部である必要があります。さて、アロケータを書くのは簡単ではありません。そして、私たちのほとんどはより良いことをし、ほとんどの場合、RAIIまたはGCで十分です。
2011-10-04を編集: 効率的なアロケーターの例:Windowsプラットフォームでは、Vista以降、 低フラグメンテーションヒープ はデフォルトで有効になっています。以前のバージョンでは、WinAPI関数 HeapSetInformation )を呼び出してLFHをアクティブ化できます。他のOSでは、代替アロケーターが提供されます(リストについては https://secure.wikimedia.org/wikipedia/en/wiki/Malloc を参照してください)
現在、マルチコアおよびマルチスレッディングテクノロジーの台頭により、メモリモデルはやや複雑になっています。この分野では、.NETに利点があると思います。Javaは上位を占めると言われました。一部の「ベアメタル」ハッカーは、「マシンに近い」コードを賞賛するのは簡単です。しかし、今では、コンパイラを仕事に任せるよりも、より良いアセンブリを手作業で作成することは非常に困難です。 C++の場合、コンパイラは通常10年以来ハッカーよりも優れたものになりました。 C#とJavaの場合、これはさらに簡単です。
それでも、新しい標準C++ 0xは単純なメモリモデルをC++コンパイラに課し、C++での効果的なマルチプロセッシング/並列/スレッドコードを標準化(したがって単純化)し、コンパイラの最適化をより簡単かつ安全にします。しかし、その後、数年後にその約束が守られているかどうかを確認します。
注:このセクションでは、C++/CLI、つまり、ネイティブC++ではなく、.NETによってホストされるC++について説明しています。
先週、.NETの最適化に関するトレーニングを受け、とにかく静的コンパイラが非常に重要であることを発見しました。 JITよりも重要です。
C++/CLI(またはその祖先であるManaged C++)でコンパイルされたまったく同じコードは、C#(またはコンパイラがC#と同じILを生成するVB.NET)で生成された同じコードよりも数倍高速です。
C++の静的コンパイラは、C#のコンパイラよりも既に最適化されたコードを生成するのに優れていたためです。
たとえば、.NETでの関数のインライン化は、バイトコードの長さが32バイト以下の関数に制限されます。そのため、C#の一部のコードは40バイトのアクセサーを生成しますが、JITによってインライン化されることはありません。 C++/CLIの同じコードは20バイトのアクセサーを生成し、JITによってインライン化されます。
別の例は一時変数です。これは、C#コンパイラーによって生成されたILでまだ言及されている間に、C++コンパイラーによって単純にコンパイルされます。 C++の静的コンパイルの最適化によりコードが少なくなるため、より積極的なJIT最適化が再び許可されます。
この理由は、C++/CLIコンパイラーがC++ネイティブコンパイラーの膨大な最適化手法から利益を得たという事実が推測されました。
私はC++が大好きです。
しかし、私が見た限りでは、C#またはJavaがすべてより良い方法です。 C++よりも高速であるためではなく、それらの品質を合計すると、C++よりも生産性が高くなり、トレーニングの必要が少なくなり、標準ライブラリがより完全になるためです。そして、ほとんどのプログラムに関しては、速度の差は(何らかの形で)無視できます...
私は現在、ほぼ独占的なプロフェッショナルなC#コーディングを5か月続けています(これは、C++とJavaで既にいっぱいのCVと、C++/CLIを少し追加したものです)。
WinForms(Ahem ...)とWCF(cool!)、WPF(Cool !!!! XAMLとraw C#の両方を使用しました。WPFはとても簡単で、Swingはそれと比較できないと思います)、C#4.0です。
結論としては、C++よりもC#/ Javaで動作するコードを作成する方が簡単/高速ですが、C#よりもC#で(さらにJavaでも)強力で安全で堅牢なコードを作成することははるかに困難です。理由はたくさんありますが、次のように要約できます。
using
でさえも、正しいDispose実装を書くことは難しいため、それほど簡単で強力ではありません。)readonly
およびJava final
は、C++のconst
ほど有用ではありません。 (読み取り専用の複雑なデータ(たとえば、ノードのツリー)をC#で公開する方法は、C++の組み込み機能でありながら、多大な作業なしではありません。不変データは興味深いソリューションですが、すべてを不変にできるわけではないため、十分ではありません。)。したがって、C#は、機能するものが必要な限り快適な言語のままですが、機能するものが必要なときはイライラする言語です 常に安全に 動作します。
JavaはC#と同じ問題を抱えているため、さらにイライラします。C#のusing
キーワードに相当するものがないため、非常に熟練した同僚がリソースを正しく解放するために時間をかけすぎました。簡単でした(デストラクタとスマートポインタを使用)。
だから、C#/ Javaの生産性の向上は、ほとんどのコードで目に見えると思います...コードを可能な限り完璧にする必要がある日まで。その日、あなたは痛みを知っているでしょう。 (サーバーおよびGUIアプリから何が求められているか信じられません...)。
建物の反対側で、サーバーチーム(GUIチームに戻る前に2年間働いていました)と連絡を取り合い、興味深いことを学びました。
昨年、Javaには多くのフレームワーク/ツールがあり、保守が容易であるため、Javaサーバーアプリを古いC++サーバーアプリに置き換える運命にありました。デプロイなど。
...低遅延の問題が最後の数ヶ月でrearい頭を育てるまで。次に、Javaサーバーアプリは、熟練したJavaチームによる最適化の試みに関係なく、実際には最適化されていない古いC++サーバーとの競争を単純かつ明確に失いました。
現在、Javaサーバーはパフォーマンスが重要でありながら低遅延のターゲットに関係なく、一般的な使用のために保持し、低遅延および超高速のために既に高速なC++サーバーアプリケーションを積極的に最適化することです。 -低遅延のニーズ。
期待したほど簡単なものはありません。
Java、さらに多くのC#は、豊富な標準ライブラリとフレームワークを備えたクールな言語であり、ここで高速にコーディングでき、すぐに結果が得られます。
しかし、生のパワー、強力で体系的な最適化、強力なコンパイラサポート、強力な言語機能、絶対的な安全性が必要な場合、JavaおよびC#を使用することで、最後に存在する必要のある重要なパーセントの品質を獲得することが難しくなります競争。
平均的な品質のコードを生成するために、C++/C++よりもC#/ Javaのほうが時間と経験の少ない開発者が必要であるかのように見えますが、一方で、優れた完璧な品質のコードが必要だった瞬間、結果を得るのは突然簡単になりましたC++で。
もちろん、これは私自身の認識であり、おそらく特定のニーズに限定されています。
それでも、GUIチームとサーバーサイドチームの両方で、今日起こっていることです。
もちろん、何か新しいことが起こったらこの投稿を更新します。
「パフォーマンスに関しては、C++が大幅に勝っています。しかし、最も広範なチューニング作業も必要でした。その多くは、平均的なプログラマにはない高度なレベルで行われました。
[...] Javaバージョンはおそらく実装が最も簡単でしたが、パフォーマンスの分析が最も困難でした。具体的には、ガベージコレクションに関する影響は複雑で、調整が非常に困難でした。」
ソース:
「Facebookに行く言葉はそれです」合理的に記述されたC++コードは高速で実行されますが、'PHPおよびJavaコードの最適化に費やされた多大な努力を強調しています。逆説的に、C++コードは他の言語よりも書くのが難しいですが、 効率的なコードは、他の言語よりもC++で書く方がはるかに簡単です。」
– ハーブサッター at // build / 、引用 Andrei Alexandresc
ソース:
マネージドパフォーマンスとアンマネージドパフォーマンスを話すときはいつでも、Rico(およびRaymond)が中国語/英語辞書のC++バージョンとC#バージョンを比較したシリーズを指すのが好きです。これは google search で読みやすくなりますが、Ricoの概要が気に入っています。
だから私は私の敗北に恥じていますか?ほとんどない。マネージコードは、ほとんど努力をせずに非常に良い結果を得ました。管理対象のレイモンドを倒すには:
- 自分でファイルI/Oを作成する
- 独自の文字列クラスを書く
- 独自のアロケーターを作成する
- 彼自身の国際的なマッピングを書く
もちろん、利用可能な低レベルのライブラリを使用してこれを行いましたが、それでも多くの作業が必要です。 STLプログラムに残っているものを呼び出すことができますか?私はそうは思わない、彼は最終的には決して問題にならなかったstd :: vectorクラスを保持し、彼は検索機能を保持したと思う。他のほとんどすべてがなくなっています。
そう、あなたは間違いなくCLRを破ることができます。レイモンドは自分のプログラムをさらに速くすることができると思います。
興味深いことに、両方のプログラムの内部タイマーによって報告されたファイルを解析する時間はほぼ同じで、それぞれ30ミリ秒です。違いはオーバーヘッドにあります。
私にとって一番下の行は、アンマネージドバージョンが元のアンマネージドコードの単純なポートであるマネージドバージョンに勝つために6つのリビジョンが必要だったことです。パフォーマンスのすべての最後のビットが必要な場合(そしてそれを得るための時間と専門知識がある場合)、管理されないようにする必要がありますが、私にとって、 %6回試すと獲得できます。
特定のCPU最適化のためのコンパイルは通常過大評価されています。 C++でプログラムを取得し、pentium PRO向けに最適化してコンパイルし、pentium 4で実行します。その後、pentium 4向けに最適化して再コンパイルします。一般的な結果??通常、パフォーマンスの向上は2〜3%未満です。したがって、理論的なJITの利点はほとんどありません。パフォーマンスのほとんどの違いは、スカラーデータ処理機能を使用する場合にのみ観察できます。スカラーデータ処理機能は、いずれにしても最大のパフォーマンスを達成するために最終的に手動で微調整が必要になるものです。この種の最適化は実行に時間がかかり、コストがかかるため、とにかくJITに適さない場合があります。
実際の世界および実際のアプリケーションでは、主にメモリのフットプリントが軽いためにキャッシュパフォーマンスが向上するため、C++は通常Javaよりも高速です。
しかし、C++のすべての機能を使用するには、開発者が一生懸命働く必要があります。優れた結果を得ることができますが、そのためにあなたの脳を使用する必要があります。 C++は、より多くのツールを提供することを決定した言語であり、その言語を上手に使用できるようにするためにツールを習得しなければならない費用がかかります。
JIT(Just In Time Compiling)は、ターゲットプラットフォーム向けに最適化されるため、非常に高速です。
これは、開発者がコードを記述したCPUに関係なく、CPUがサポートできるコンパイラートリックを活用できることを意味します。
.NET JITの基本概念は次のように機能します(大幅に簡略化されています)。
初めてメソッドを呼び出す:
2回目のメソッド呼び出し:
ご覧のとおり、2回目は、C++とほぼ同じプロセスですが、リアルタイム最適化の利点があります。
そうは言っても、マネージド言語の速度を落とすオーバーヘッド問題はまだありますが、JITは大いに役立ちます。
Orion Adrian の答えが好きですが、別の側面があります。
何十年も前に、アセンブリ言語とFORTRANのような「人間」言語について同じ問題が提起されました。そして、答えの一部は似ています。
はい、C++プログラムは任意の(自明ではない?)アルゴリズムでC#よりも高速ですが、C#のプログラムは多くの場合、C++の「単純な」実装やC++の最適化バージョンと同じか高速です。開発に時間がかかりますが、C#バージョンをわずかに上回る可能性があります。だから、それは本当に価値がありますか?
その質問に1つずつ答える必要があります。
とはいえ、私はC++の長年のファンであり、C++は信じられないほど表現力豊かで強力な言語だと思います。しかし、多くの「現実の」問題(個人的には、「解決するための報酬」を意味します)では、C#が仕事をより早く、より安全に処理します。
あなたが支払う最大のペナルティは?多くの.NETおよびJavaプログラムはメモリを大量に消費します。 .NETおよびJavaアプリは、同様の複雑さのC++プログラムが "数十" MBをかろうじて「何百」メガバイトのメモリを取ることを見てきました。
Hotspotを使用した場合でも、JavaコードがC++よりも高速に実行される頻度はわかりませんが、どのように発生するかを説明します。
コンパイルされたJavaコードは、JVMの解釈されたマシン言語と考えてください。 Hotspotプロセッサは、コンパイルされたコードの特定の部分が何度も使用されることに気付くと、マシンコードの最適化を実行します。アセンブリの手動調整はC++でコンパイルされたコードよりもほとんど常に高速であるため、プログラムで調整されたマシンコードがtoo badにならないことを理解することは問題ありません。
そのため、非常に反復性の高いコードの場合、ガベージコレクションが実行されるまで、Hotspot JVMがJavaをC++よりも高速に実行できる場所がわかりました。 :)
一般的に、プログラムのalgorithmは、アプリケーションの速度にとってlanguageよりもはるかに重要です。 C++を含む任意の言語で貧弱なアルゴリズムを実装できます。それを念頭に置いて、一般に、より効率的なアルゴリズムを実装するのに役立つ言語で、より速く実行するコードを書くことができます。
高レベルの言語は、多くの効率的な事前構築されたデータ構造へのアクセスを容易にし、非効率なコードを避けるのに役立つプラクティスを奨励することにより、これで非常にうまく機能します。もちろん、時には非常に遅いコードの束を簡単に書くこともできるので、プラットフォームを知る必要があります。
また、C++は、STLコンテナ、自動ポインタなどの「新しい」(引用符に注意)機能に追いついています。たとえば、boostライブラリを参照してください。そして、いくつかのタスクを達成するための最速の方法は、高水準言語では禁止されているポインター演算のような技術を必要とすることが時々ありますが、通常は、必要に応じてそれを実装できる言語で書かれたライブラリーを呼び出すことができます。
主なことは、使用している言語、関連付けられているAPI、実行できること、制限事項を知ることです。
私もわからない...私のJavaプログラムは常に遅い。 :-)しかし、C#プログラムが特に遅いことに気付いたことはありません。
「...よりも優れたパフォーマンス」を定義する必要があります。まあ、私は知っています、あなたは速度について尋ねました、しかしそれは重要なすべてではありません。
など、そのバイアス、はい;)
C#とJavaを使用すると、得られるもの(より速いコーディング、自動メモリ管理、大きなライブラリなど)に対して代価を支払います。しかし、あなたは詳細について口論する余地があまりありません。完全なパッケージを取るか、何もしません。
これらの言語が一部のコードを最適化してコンパイル済みコードよりも高速に実行できる場合でも、全体的なアプローチは(IMHO)非効率的です。トラックで毎日5マイル、職場まで運転することを想像してください!快適で、心地よく、安全です(極端なしわくちゃのゾーン)。しばらくガソリンを踏んだ後は、標準的な車と同じくらい速くさえあります。なぜ私たち全員が仕事のために運転するトラックを持っていないのですか? ;)
C++では、より多くではなく、より多くではなく、あなたが支払うものを手に入れます。
Bjarne Stroustrupの引用:「C++は、ごみがほとんど生成されないため、私のお気に入りのごみ収集言語です」 リンクテキスト
ここに別の興味深いベンチマークがあります。これは自分のコンピューターで試してみることができます。
ASM、VC++、C#、Silverlight、Javaアプレット、Javascript、Flash(AS3)を比較します
Javascriptの速度は、実行しているブラウザに応じて大きく変化することに注意してください。 FlashとSilverlightについても同じことが言えます。これらのプラグインは、ホストしているブラウザーと同じプロセスで実行されるためです。しかし、Roozzプラグインは独自のプロセスで実行される標準の.exeファイルを実行するため、速度はホスティングブラウザーの影響を受けません。
あなたが尋ねた特定の質問についていくつかの良い答えがあります。一歩下がって、全体像を見てみたいと思います。
作成するソフトウェアの速度に対するユーザーの認識は、codegenの最適化以外の多くの要因の影響を受けることに注意してください。ここではいくつかの例を示します。
手動のメモリ管理は正しく行うのが難しく(リークなし)、効率的に行うのがさらに難しくなります(使い終わったらすぐにメモリを解放します)。一般に、GCを使用すると、メモリを適切に管理するプログラムが作成される可能性が高くなります。 GCをしのぐために、一生懸命仕事をして、ソフトウェアの配布を遅らせますか?
私のC#は、C++よりも読みやすく、理解しやすいです。また、自分のC#コードが正しく機能していることを確信させる方法が他にもあります。これは、バグを導入するリスクを抑えてアルゴリズムを最適化できることを意味します(そして、ユーザーがクラッシュするソフトウェアは、たとえそれがすぐに実行されても嫌いです!)
C++よりもC#でソフトウェアを高速に作成できます。そうすることで、時間を空けてパフォーマンスに取り組むことができ、しかもソフトウェアを予定どおりに提供できます。
C++よりもC#で優れたUIを記述する方が簡単です。そのため、UIの応答性を維持しながら作業をバックグラウンドにプッシュしたり、プログラムをしばらくブロックする必要がある場合に進行状況や聞こえるUIを提供したりする可能性が高くなります。これは何も速くしませんが、それはユーザーが待つことをより幸せにします。
C#について私が言ったことはすべて、おそらくJavaに当てはまります。確かに言う経験はありません。
Orion Adrian 、C++についても多くのことが言えるので、あなたの投稿を反転させて、あなたの発言がどれほど根拠のないものであるかを見てみましょう。そして、Java/C#コンパイラが空の関数を最適化することで、あなたは本当に最適化の専門家ではないように聞こえますではない非常に悪いレガシコードの場合、b)それは本当に黒ではなく、Edge最適化を出血させます。
そのフレーズとは別に、ポインターについて露骨に暴言しましたが、JavaおよびC#のオブジェクトは基本的にC++ポインターのように機能しませんか?重ならないようにできますか?ヌルではないかもしれませんか? C(およびほとんどのC++実装)にはrestrictキーワードがあり、両方に値型があり、C++にはnull以外の保証のある値への参照があります。 JavaとC#は何を提供しますか?
一般に、CおよびC++は、AOTコンパイラ(展開前にコードをコンパイルするコンパイラであるため、高メモリの多くのコアビルドサーバー上で)C#でコンパイルされたプログラムが最適化できるため、CとC++は同じくらい高速または高速になります。それには時間がかかりすぎます。コンパイラは、マシンがIntelかAMDかを判断できます。 Pentium 4、Core Solo、またはCore Duo。または、SSE4などをサポートしており、コンパイラがランタイムディスパッチをサポートしていない場合は、少数の特殊なバイナリを展開することでその問題を解決できます。
AC#プログラムは通常、実行時にコンパイルされるため、すべてのマシンで適切に実行されますが、単一の構成(つまり、プロセッサ、命令セット、その他のハードウェア)ほど最適化されていませんmust最初に時間を費やす必要があります。ループ核分裂、ループ反転、自動ベクトル化、プログラム全体の最適化、テンプレート拡張、IPOなどの機能は、エンドユーザーを困らせない方法ですべて完全に解決するのは非常に困難です。
さらに、特定の言語機能により、C++またはCのコンパイラーは、Java/C#コンパイラーにとって安全ではない特定の部分を最適化できるように、コードに関する仮定を行うことができます。ジェネリックの完全なタイプIDまたは保証されたプログラムフローにアクセスできない場合、多くの最適化が安全ではありません。
また、C++およびCは、1つのレジスタ増分で一度に多くのスタック割り当てを行います。これは、ガベージコレクタとコード間の抽象化層に関して、JavaおよびC#割り当てよりも確実に効率的です。
この次の点でJavaについて話すことはできませんが、たとえばC++コンパイラは、メソッドの本体が空であることを知っているときに実際にメソッドとメソッド呼び出しを削除し、一般的な部分式を削除することを知っています、最適なレジスタの使用を見つけるために再試行を試みる場合があります。境界チェックを実施せず、ループと内部ループを自動ベクトル化し、内部から外部に反転します。 Cの方法と同じように、std :: vectorをネイティブのゼロオーバーヘッド配列に展開します。手続き間の最適化を行います。呼び出し元のサイトで戻り値を直接構築します。式を折りたたみ、伝播します。キャッシュに優しい方法でデータを並べ替えます。ジャンプスレッディングを行います。これにより、ランタイムオーバーヘッドなしでコンパイルタイムレイトレーサを作成できます。非常に高価なグラフベースの最適化を行います。特定のコードを構文的に完全に等しくないが意味的に同等のコードで置き換えると、強度が低下します(古い「xor foo、foo」は、そのような種類の時代遅れの最適化ですが、最も単純です)。親切に尋ねる場合は、IEEE浮動小数点標準を省略して、浮動小数点オペランドの並べ替えなど、さらに多くの最適化を有効にすることができます。コードをマッサージして虐殺した後、プロセス全体を繰り返す場合があります。多くの場合、特定の最適化がさらに特定の最適化の基礎を築くからです。また、シャッフルされたパラメーターで再試行し、他のバリアントが内部ランキングでどのようにスコアリングするかを確認することもできます。そして、コード全体でこの種のロジックを使用します。
ご覧のとおり、特定のC++またはCの実装が高速になる理由はたくさんあります。
これですべて、C#でできることは何でも吹き飛ばされる多くの最適化がC++で行えるようになりました。特に、数値計算、リアルタイム、および金属に近い領域で、しかしそこだけではありません。長い道のりを歩むために、1つのポインターに触れる必要さえありません。
あなたが書いているものに応じて、私はどちらか一方と一緒に行くでしょう。ただし、ハードウェアに依存しないもの(ドライバー、ビデオゲームなど)を作成している場合、C#のパフォーマンスについては心配しません(Javaについて話すことはできません)。それはうまくいくでしょう。
一般的に、特定の投稿では特定の一般化された引数はクールに聞こえるかもしれませんが、一般的に確かに信頼できるとは限りません。
とにかく、平和を作るために:AOTは素晴らしいです。JIT 。唯一の正しい答えは次のとおりです。そして、本物の賢い人は、とにかく両方の長所を使用できることを知っています。
C++を学習しているJava/C#プログラマーであれば、Java/C#の観点から考え続け、逐語的にC++構文に変換したくなるでしょう。その場合、先ほど述べたネイティブコードとインタープリタ/ JITの利点のみが得られます。 C++対Java/C#で最大のパフォーマンス向上を得るには、C++で考え、C++の長所を活用するためのコードを設計することを学ぶ必要があります。
言い換えると Edsger Dijkstra :[あなたの第一言語]は回復を超えて心を傷つけます。
言い換えると Jeff Atwood :[あなたの第一言語]を新しい言語で書くことができます。
最も重要なJIT最適化の1つは、メソッドのインライン化です。 Javaは、実行時の正確性を保証できる場合、仮想メソッドをインライン化することもできます。この種の最適化は、通常、標準の静的コンパイラでは実行できません。これは、プログラム全体の分析が必要であるためです。メソッドのインライン化により、他の最適化が改善され、最適化するためのコードブロックが大きくなります。
Java/C#の標準メモリ割り当ても高速で、割り当て解除(GC)はそれほど遅くはありませんが、決定論的ではありません。
JavaまたはC#コンパイラから生成された実行可能コードは解釈されません。ネイティブコード「ジャストインタイム」(JIT)にコンパイルされます。そのため、実行中にJava/C#プログラムの最初のコードが検出されると、「ランタイムコンパイラ」(別名JITコンパイラ)がバイトコード(Java)またはILコード(C#)をネイティブマシン命令に変換するため、オーバーヘッドが発生します。ただし、アプリケーションの実行中にコードが次に検出されると、ネイティブコードがすぐに実行されます。これは、一部のJava/C#プログラムが最初は遅いように見えますが、実行時間が長くなるほどパフォーマンスが向上することを説明しています。良い例がASP.Net Webサイトです。 Webサイトに初めてアクセスするときは、C#コードがJITコンパイラーによってネイティブコードにコンパイルされるため、少し遅くなる場合があります。その後のアクセスにより、Webサイトがはるかに高速になります(サーバー側とクライアント側のキャッシュは別として)。
仮想マシンの言語は、コンパイルされた言語を上回る可能性は低いですが、(少なくとも)次の理由により、問題にならない程度に近づくことができます(私はこれまでにJavaについて話している完了C#)。
1/Java Runtime Environmentは通常、頻繁に実行されるコードの一部を検出し、それらのセクションのジャストインタイム(JIT)コンパイルを実行できるため、将来、完全にコンパイルされた状態で実行されます速度。
2/Javaライブラリの大部分はコンパイルされるため、ライブラリ関数を呼び出すと、コンパイルされたコードが実行され、解釈されません。 OpenJDKをダウンロードすると、コード(Cで)を見ることができます。
3 /大規模な計算を行っていない限り、プログラムが実行されているほとんどの時間は、非常に遅い(比較的話す)人間からの入力を待っています。
4/Javaバイトコードの検証の多くがクラスのロード時に行われるため、ランタイムチェックの通常のオーバーヘッドが大幅に削減されます。
5 /最悪の場合、パフォーマンス重視のコードをコンパイル済みモジュールに抽出し、Java(JNIを参照)から呼び出して、最高速度で実行できるようにすることができます。
要約すると、Javaバイトコードはネイティブマシン言語を決して上回ることはありませんが、これを軽減する方法があります。 Javaの大きな利点(おわかりのように)は、HUGE標準ライブラリとクロスプラットフォームの性質です。
実際、C#はJavaのように仮想マシンで実際には実行されません。 ILは、完全にネイティブコードであるアセンブリ言語にコンパイルされ、ネイティブコードと同じ速度で実行されます。 JITコストを完全に削除する.NETアプリケーションを事前JITできます。その後、完全にネイティブコードを実行します。
.NETが遅くなるのは、.NETコードが遅いためではありませんが、ガベージコレクション、参照のチェック、完全なスタックフレームの保存などを行うためにバックグラウンドで多くのことを行うためです。アプリケーションを構築するだけでなく、コストがかかります。これらすべてをC++プログラムでも実行できることに注意してください(.NETのコア機能の多くは、実際にはROTORで表示できる.NETコードです)。ただし、同じ機能を手動で記述した場合、.NETランタイムが最適化され、微調整されているため、おそらくはるかに遅いプログラムになります。
ただし、マネージコードの長所の1つは、完全に検証可能であることです。コードを実行する前に、コードが他のプロセスのメモリに決してアクセスしないことを確認したり、アンサージュを行ったりすることができます。マイクロソフトには、完全に管理されたオペレーティングシステムの研究プロトタイプがあり、100%管理された環境は、この検証を利用してマネージプログラムで不要になったセキュリティ機能をオフにすることで、実際に最新のオペレーティングシステムよりも大幅に高速に実行できることが示されています(場合によっては10倍のように話します)。 SEラジオには、このプロジェクトに関する素晴らしいエピソードがあります。
Javaインタープリターが実際にbetter作成しているC++コード用にコンパイラーが生成しているマシンコードよりも最適化されたマシンコードを生成している場合にのみ発生します。 C++コードはJavaおよび解釈コストよりも低速です。
ただし、実際に発生する可能性は非常に低く、おそらくJavaに非常によく記述されたライブラリがあり、独自に作成が不十分なC++ライブラリがある場合を除きます。
実際、SunのHotSpot JVMは「混合モード」実行を使用します。特定のコードブロック(メソッド、ループ、try-catchブロックなど)が大量に実行されると(通常はある種のカウンターを介して)判断されるまで、メソッドのバイトコードを解釈し、JITコンパイルします。メソッドのJITコンパイルに必要な時間は、メソッドがめったに実行されないメソッドであると解釈される場合よりも時間がかかることがよくあります。 JVMは通常、実行されることはめったにないJITコードの時間を無駄にしないため、「混合モード」のパフォーマンスは通常高くなります。 C#と.NETはこれを行いません。 .NET JITは、多くの場合、時間を浪費するすべてのものを処理します。
JavaまたはCLRがC++よりも速い場合、短いバーストが発生する可能性がありますが、アプリケーションの寿命全体ではパフォーマンスが低下します。結果についてはwww.codeproject.com/KB/dotnet/RuntimePerformance.aspxを参照してくださいそのために。
Cliff Clickからの回答を次に示します。 http://www.azulsystems.com/blog/cliff/2009-09-06-Java-vs-c-performanceagain
HP-Labsの Dynamo を読んでください。PA-8000で動作するPA-8000のインタープリターであり、多くの場合、ネイティブよりも高速にプログラムを実行します。そうすれば、まったく驚くことではないでしょう!
「中間ステップ」とは考えないでください。プログラムを実行するには、他の多くのステップがあらゆる言語ですでに含まれています。
多くの場合、次のようになります。
プログラムにはホットスポットがあるため、実行する必要のあるコード本体の95%の実行速度が遅くても、ホット5%の速度が速い場合は、パフォーマンスの競争力を維持できます。
hLLはC/C++のようなLLLよりもあなたの意図をよく知っているので、より最適化されたコードを生成できます(OCamlにはさらに多くの機能があり、実際にはより高速です)
jITコンパイラーには、静的コンパイラーにはない多くの情報があります(たまたま実際に持っているデータなど)
jITコンパイラーは、実行時に従来のリンカーでは実際に許可されていない最適化を実行できます(一般的なケースがフラットになるようにブランチを並べ替える、またはライブラリー呼び出しをインライン化するなど)
全体として、C/C++はパフォーマンスに関してかなりお粗末な言語です。データ型に関する情報は比較的少なく、データに関する情報はなく、ランタイム最適化の方法で多くのことを可能にする動的ランタイムもありません。
私の理解では、C/C++は特定のマシンアーキテクチャで実行するネイティブコードを生成します。逆に、JavaやC#などの言語は、ネイティブアーキテクチャを抽象化する仮想マシン上で実行されます。論理的には、この中間ステップのためにJavaまたはC#がC++の速度に一致することは不可能に思えますが、最新のコンパイラ(「ホットスポット」)はこの速度に達するか、それ。
それは非論理的です。中間表現を使用しても、本質的にパフォーマンスが低下することはありません。たとえば、llvm-gccはLLVM IR(仮想無限レジスタマシン)を介してCおよびC++をネイティブコードにコンパイルし、優れたパフォーマンス(多くの場合GCCを破る)を実現します。
おそらくこれは言語の質問よりもコンパイラーの質問の方が多いかもしれませんが、これらの仮想マシン言語の1つがネイティブ言語よりも優れたパフォーマンスを発揮する方法を英語で説明できますか?
ここではいくつかの例を示します。
JITコンパイルを備えた仮想マシンは、ランタイムコード生成(.NETのSystem.Reflection.Emit
など)を促進するため、生成されたコードをC#やF#などの言語でオンザフライでコンパイルできますが、 CまたはC++。たとえば、正規表現を実装します。
CとC++は十分な速度のコードを生成しないため、仮想マシンの一部(書き込みバリアやアロケーターなど)は、多くの場合、手動でコーディングされたアセンブラーで記述されます。プログラムがシステムのこれらの部分に負荷をかけると、CまたはC++で記述できるものよりもパフォーマンスが優れている可能性があります。
ネイティブコードの動的リンクには、パフォーマンスを妨げ、プログラム全体の最適化を不要にするABIに準拠する必要がありますが、通常、リンクはVMで延期され、プログラム全体の最適化(.NETの具体化ジェネリックなど)の恩恵を受けることができます。
また、上記のpaecebalの非常に支持された回答に関するいくつかの問題に対処したいと思います(誰かが彼の回答に関する私のコメントを削除し続けるため)。
コード処理はコンパイル時に行われます...
したがって、テンプレートのメタプログラミングは、プログラムがコンパイル時に利用可能な場合にのみ機能します。実行時コード生成(メタプログラミングの重要な側面)ができないため、Vanilla C++で競争力のある正規表現ライブラリを作成することはできません。
...型の再生はコンパイル時に行われます... JavaまたはC#の同等の記述は、せいぜい苦痛であり、コンパイル時に型がわかっていても、実行時に常に遅くなり、解決されます時間。
C#では、これは参照型にのみ当てはまり、値型には当てはまりません。
JIT最適化に関係なく、メモリへの直接ポインタアクセス...メモリ内に連続したデータがある場合、C++ポインタ(つまり、Cポインタ... Caesarに期限を与えましょう)を介してアクセスすると、何倍も速くなります。 Java/C#よりも。
JavaがSciMark2ベンチマークのSORテストでC++を破っている が、ポインターがエイリアシング関連の最適化を妨げるためです。
また、リンク後に動的にリンクされたライブラリ全体で.NETがジェネリック型の特殊化を行うのに対し、C++はリンクする前にテンプレートを解決する必要があるためできないことにも注意してください。そして明らかに、ジェネリックがテンプレートよりも優れている大きな利点は、わかりやすいエラーメッセージです。
場合によっては、マネージコードは実際にはネイティブコードより高速になります。たとえば、「マークアンドスイープ」ガベージコレクションアルゴリズムを使用すると、JREやCLRなどの環境で、ほとんどのC/C++ヒープオブジェクトが1回で解放される、単一パスで多数の短命(通常)オブジェクトを解放できます。時間。
wikipedia から:
多くの実用的な目的のために、ガベージコレクションされた言語で実装された割り当て/割り当て集約型のアルゴリズムは、実際には、手動ヒープ割り当てを使用した同等のアルゴリズムよりも高速です。これの主な理由は、ガベージコレクタにより、ランタイムシステムが潜在的に有利な方法で割り当て操作と割り当て解除操作を償却できることです。
そうは言っても、私はたくさんのC#とたくさんのC++を書き、たくさんのベンチマークを実行しました。私の経験では、C++は2つの方法でC#よりもはるかに高速です:(1)C#で記述したコードを使用する場合、ネイティブコードtendsより高速に。どれくらい速い?まあ、それは大きく異なりますが、100%の速度向上が見られることは珍しくありません。 (2)場合によっては、ガベージコレクションによって管理対象アプリケーションの速度が大幅に遅くなることがあります。 .NET CLRは大きなヒープ(2 GBを超えるなど)でひどい仕事をしており、GCで多くの時間を費やしている可能性があります(中間寿命のオブジェクトがほとんどない、またはまったくないアプリケーションでも)。
もちろん、私が遭遇したほとんどの場合、マネージド言語は長い時間をかけて十分に高速であり、C++のパフォーマンスを向上させるためのメンテナンスとコーディングのトレードオフは、単に良いものではありません。
多くの速度を必要とするものについては、JVMはC++実装を呼び出すだけなので、ほとんどのOS関連のものに対してJVMがどれほど優れているかというよりも、ライブラリがどれだけ優れているかという問題です。ガベージコレクションはメモリを半分に削減しますが、より洗練されたSTLおよびBoost機能の一部を使用しても同じ効果がありますが、バグの可能性が何度もあります。
多くのクラスを含む大規模プロジェクトでC++ライブラリとその高レベル機能の多くを使用している場合は、おそらくJVMを使用するよりも時間がかかります。より多くのエラーが発生する可能性があります。
ただし、C++の利点は、自分で最適化できることです。そうしないと、コンパイラ/ jvmの機能にこだわることになります。独自のコンテナを作成し、調整された独自のメモリ管理を記述し、SIMDを使用し、あちこちにアセンブリをドロップすると、ほとんどのC++コンパイラが単独で行う処理よりも少なくとも2倍から4倍高速化できます。一部の操作では、16x-32x。それは同じアルゴリズムを使用しているため、より良いアルゴリズムを使用して並列化すると、劇的に増加することがあり、一般的に使用される方法の数千倍も速い場合があります。
最近は、すべてのマルチコアプロセッサが市場に投入された後、サーバーの処理速度に関してパフォーマンスを考慮する必要はないと思います。メモリ使用量に基づいて、さらに定義する必要があります。そして、その方法Javaにはわずかな欠点があります。
しかし、すべてのプログラミング言語のすべてが、異なる目的に適しています。そして、それは彼らの競争領域であり、各セクションでは異なる勝者です。
そして、Javaは、それが生み出すすべての新機能で示される開発と競争力を継続しているため、長期的に勝つと確信しています。
Javaに投票する理由をサポートする link が見つかりました
非常に短い答え:固定予算が与えられると、C++アプリケーションよりも優れたパフォーマンスのJavaアプリケーションを達成できます(ROIの考慮事項)さらに、Javaプラットフォームには、適切なプロファイラーがあり、これによりピンポイントを特定できますホットスポットをより迅速に
いくつかの異なる点から見ていきます。
他の人が言ったことに加えて、私の理解では、.NETとJavaはメモリ割り当ての方が優れています。例えば。 C++ではフラグメント化できないのでメモリを圧縮できます(ネイティブではありますが、賢いガベージコレクターを使用している場合は可能です)。