a。今日のJavaの速度はC ++と比較してどうですか?
測定が難しい。実装の速度の大部分であるメモリアロケータは、JavaとC ++の非常に異なるアルゴリズムであることは注目に値します。コレクターの非決定的性質により、C ++の決定論的メモリー管理と比較して、意味のあるパフォーマンスデータを取得することが非常に困難になります。コレクターの状態を確認できないためです。意味のある比較をするかもしれません。一部のメモリ割り当てパターンはGCではるかに高速に実行され、一部はネイティブアロケーターではるかに高速に実行されます。
ただし、Java GCはあらゆる状況で高速に実行する必要があるということです。ただし、ネイティブアロケーターは、より適切なものに交換できます。私は最近、C#が同等のものと比較して(私のマシンでは0.45ミリ秒で)実行できる理由についてSOに質問をしましたDictionary
std::unordered_map
実行しました(私のマシンでは10ms)。ただし、アロケータとハッシュをより適切なものに交換するだけで、マシン上で実行時間を0.34msに短縮しました。これは元のランタイムの30分の1です。Javaでそのようなカスタム最適化を実行することは決して望めません。これが実際の違いを生むことができる優れた例は、スレッド化です。TBBのようなネイティブスレッドライブラリは、多くのスレッドで多くの割り当てを処理する場合、従来のアロケーターよりも非常に高速なスレッドキャッシングアロケーターを提供します。
次に、多くの人々がJITの改善と、JITがより多くの情報を持っている方法について話します。確かに、それは本当です。しかし、C ++コンパイラは、最終プログラムの実行時間の観点から、実行する時間とスペースが比較的無限であるため、C ++コンパイラが引き出せるものにまだ遠くありません。JITがプログラムを最適化する最適な方法を考えるために費やすすべてのサイクルとバイトは、プログラムが実行に費やしておらず、独自のメモリニーズに使用できないサイクルです。
さらに、コンパイラーとJITの最適化が特定の最適化を証明できない場合が常にあります(特に、エスケープ分析などの場合)。C ++では、とにかく値がスタック上にあるので、コンパイラーはそれを実行する必要はありません。さらに、連続メモリのような単純なものがあります。C ++で配列を割り当てる場合、単一の連続した配列を割り当てます。Javaで配列を割り当てた場合、配列はどこにも指すことができないポインターで満たされるだけなので、配列はまったく連続していません。これは、二重間接のメモリおよび時間のオーバーヘッドだけでなく、キャッシュのオーバーヘッドでもあります。この種のことは、Javaの言語セマンティクスが、同等のC ++コードよりも遅くなければならないことを強制するだけです。
最終的に、私の個人的な経験では、Javaは平均してC ++の約半分の速度になる可能性があります。ただし、実際にはアルゴリズムが根本的に異なるため、非常に包括的なベンチマークスイートがないとパフォーマンスステートメントをバックアップする方法はありません。
b。Javaを使用して最新のAAAタイトルを作成することは可能でしょうか?
ここでは「チャンス」ではなく「ゲーム」を意味すると思います。まず、既存のライブラリとインフラストラクチャのほとんどすべてがC ++を対象としているため、すべてをゼロから作成する必要があります。それ自体を不可能にするわけではありませんが、確実に実現不可能なものに貢献する可能性があります。第二に、C ++エンジンでさえも、既存のコンソールの小さなメモリの制約に収まらない場合があります(JVMがそれらのコンソールに存在する場合でも)。そして、PCゲーマーはメモリにもう少し期待しています。パフォーマンスの高いAAAゲームを作成することはC ++では十分に困難であり、Javaでどのように実現できるかわかりません。コンパイルされていない言語でかなりの時間を費やしてAAAゲームを書いた人は誰もいません。それ以上に、単純に非常にエラーが発生しやすくなります。たとえば、GPUリソースを処理する場合、確定的な破壊は不可欠です。Javaでは、
c。JavaがC ++より遅いのは、具体的にどのような分野ですか?(つまり、数値演算、グラフィックス、またはその周辺)
私は間違いなく万能に行きたいです。すべてのJavaオブジェクトの強制参照の性質は、JavaがC ++よりもはるかに多くの間接性と参照を持っていることを意味します。以前に配列で示した例は、すべてのメンバーオブジェクトにも適用されます。C ++コンパイラが一定時間でメンバー変数を検索できる場合、Javaランタイムは別のポインターをたどる必要があります。アクセス回数が多いほど、取得速度は遅くなり、JITがそれに対してできることは何もありません。
C ++がメモリの一部をほぼ瞬時に解放して再利用できる場合、Javaではコレクションを待つ必要があります。キャッシュがなくなることはなく、本質的に多くのメモリが必要になると、キャッシュとページングのパフォーマンスが低下します。次に、ボクシングやボックス解除などのセマンティクスを調べます。Javaでは、intを参照する場合、動的に割り当てる必要があります。これは、C ++のセマンティクスと比較して固有の無駄です。
次に、ジェネリックの問題があります。Javaでは、実行時継承を介してのみ汎用オブジェクトを操作できます。C ++では、テンプレートのオーバーヘッドは文字通りゼロであり、Javaには対応できません。つまり、Javaのすべての汎用コードは、C ++の一般的な同等のコードよりも本質的に低速です。
そして、あなたは未定義の行動に来ます。彼らのプログラムがUBを展示するとき、誰もがそれを嫌い、誰もがそれが存在しなかったことを望みます。ただし、UBは基本的に、Javaには決して存在しない最適化を可能にします。UBに基づいた最適化について説明しているこの投稿をご覧ください。動作を定義しないということは、実装がより多くの最適化を行い、C ++では定義されないがJavaで定義される条件をチェックするために必要なコードを削減できることを意味します。
基本的に、Javaのセマンティクスは、JavaがC ++よりも遅い言語であることを示しています。
Javaは現在、コンパイル言語またはインタープリター言語と見なされていますか?
これらのグループのいずれにも当てはまりません。マネージドは、それ自体が実際には別のカテゴリであると思いますが、コンパイルされた言語というよりもインタプリタ言語に間違いなく似ていると思います。さらに重要なことは、JVMとCLRという2つの主要な管理対象システムしかないことです。「管理対象」と言えば、それは十分に明確です。
初期の頃から対処されてきたJavaの主な欠点は何ですか?
私が知っているのは、自動ボクシングとアンボクシングだけです。ジェネリックはいくつかの問題を解決しますが、多くの問題からはほど遠いです。
まだ対処されていないJavaの主な欠点は何ですか?
それらのジェネリックは非常に弱いです。C#のジェネリックはかなり強力です-もちろん、どちらもまったくテンプレートではありません。決定論的な破壊はもう1つの大きな欠如です。どんな形式のラムダ/クロージャーも大きな問題です。Javaの機能的なAPIを忘れることができます。そしてもちろん、それを必要とする分野には常にパフォーマンスの問題があります。