Javaの性能

Javaの性能（ジャバのせいのう）の記事では、Javaプラットフォームの性能について説明する。プログラミング言語としてのJavaに対する批判や、Javaプラットフォームの性能に対する批判は「Javaに対する批判」の記事を参照のこと。この記事ではJavaプラットフォームの性能について批判以外の説明をする。
プログラミング言語Javaは、その「ネットワークから送り込まれるプログラムの安全な実行」や「write once, run anywhere」というスローガンを、業界にありがちなスローガンだけのスローガンではなく可能な限り達成するべく、Javaバイトコードにコンパイルするコンパイラと、Javaバイトコードを解釈実行するインタプリタであるJava仮想マシン (JVM)、という構成の実装を、公式の実装として伴って発表された。
コンピュータ科学的には特に目新しいものではない。しかし「C言語に代わる言語」といったように業界メディアが煽ったことなどにより、ネイティブコードにコンパイルされた場合との比較や、当初はJVMのチューニングや高速化手法が進んでいなかったことによる性能の制限、また、当時の一般ユーザーが使っていたマイクロソフト・インターネット・エクスプローラーにおいて、Javaアプレットが埋込まれたウェブページを表示しようとすると、JVMを起動するために数十秒から最悪の場合は数分も待たされたことから（起動してしまえば実は高性能なVMだったのだが）、「Javaは遅い」などと言われるようになったため、「Javaの性能」が議論されるようになった。
Javaプログラムの実行速度はJITコンパイルの導入（1997年 / 1998年のJava 1.1以降）や

、
コードの解析の機能が言語に追加されたこと、Java仮想マシン自体の最適化（2000年からサン・マイクロシステムズのVMで標準的に動作するようになったHotSpot技術など）によって大きく向上した。

仮想マシンの最適化手法

様々な最適化技術によりJava仮想マシンの性能は徐々に向上してきたが、Javaはいくつかの最適化技術を実装した最初の仮想機械であることも多く、そうした技術は類似のプラットフォームでも使用されている。

ジャストインタイムコンパイル

初期のJava仮想マシンはバイトコードのインタプリタであり、このことが性能に対する大きな足かせ（平均的なアプリケーションで、Java対Cで10〜20倍程度）になっていた。
Java 1.1で JIT コンパイラが導入された。
Java 1.2でHotSpotと呼ばれる技術が導入された。これは、Java仮想マシンがプログラムの頻繁に実行される箇所、「ホットスポット」の性能解析を実行中に実行し続けるもので、解析した情報は最適化に利用して、他のパフォーマンスに影響のないコードには余分な負荷をかけることなく、性能を向上させることができる。
Java 1.3でHotSpotが標準で用いられるようになった。
HotSpot技術により、コードはまずインタプリタ実行され、「ホットスポット」が動的にコンパイルされる。Javaの性能測定においてベンチマークをとる前にプログラムを数回実行させる必要があるのはこのためである。
HotSpotによるコンパイルではインライン展開、ループ展開、境界チェックの省略、アーキテクチャ固有のレジスタ割り付けなどの様々な最適化手法が用いられる。
ベンチマークによってはこうした手法により10倍の性能向上が見られる。

適応的最適化

適応的最適化とは、計算機科学においてプログラムの一部を現在の実行結果のプロファイルに基づき動的再コンパイルする技術である。単純な実装では、適応的最適化はジャストインコンパイルとインタプリタ実行を選択するだけだが、より高水準のものでは、データの局所的な状態を用いて分岐を取り除き、インライン展開してコンテキスト切り替えを削減することもできる。
HotSpotのようなJava仮想マシンは、一度JITコンパイルされたコードを解消することも可能である。これによって、積極的な（場合によっては危険な）最適化を実行し、後で最適化を解消し安全な実行方法に戻ることもできる。

ガベージコレクション

Java 1.0と1.1のJava仮想マシン では、ガベージコレクション実行後のヒープが断片化する可能性のあるマーク・アンド・スイープ方式のガベージコレクションを採用していた。
Java 1.2より、Java仮想マシンは世代別ガベージコレクションを用いるようになり、断片化が起こりづらくなった。
現代的なJava仮想マシンは、ガベージコレクションの性能を改善する様々な手法を用いている。

レジスタ割付の改善

Java 6以前では、「クライアント」仮想マシンにおけるレジスタ割り付けはかなり初歩的なもので（ブロックを超えてレジスタが生存できない）、これは例えばx86のようなレジスタが少ないアーキテクチャで問題となる。ある操作に必要なレジスタが足りなくなると、コンパイラはレジスタからメモリ（ないしはメモリからレジスタ）に値をコピーするが、メモリは通常レジスタより低速なので、通常より時間がかかる。なお「サーバ」仮想マシンではグラフ彩色によるレジスタ割り付けを行うため、こうした問題は生じない。
レジスタ割り付けの最適化はサンのJDK 6で導入された。これは同じレジスタを、可能な場合コードブロックをまたがって使用することでメモリアクセスを減らすもので、報告によればいくつかのベンチマークで約60%の性能向上が得られた。

クラスデータの共有

クラスデータの共有（オラクルはCDSと呼んでいる）とは、Javaアプリケーションの起動時間を短くし、同時にメモリ使用量を削減する仕組みである。JREがインストールされると、インストーラーはシステム Jarファイル（Java のクラスライブラリを全て含むJarファイルで、rt.jarと呼ばれる）からいくつかのクラスを特別な内部表現形式でロードし、この内部表現を「共有書庫」ファイルとして書き出す。それ以降のJVMの呼び出し時には、共有書庫ファイルはメモリマップされ、これによってクラスをロードする時間を短縮し、複数 JVM プロセスがこれらのクラスのメタデータを共有できるようになる。
起動時間の短縮は、特に小さなプログラムで効果が著しい。

Sun の Java バージョンによる性能の向上

上記以外にも、オラクルのJavaは各バージョンでJava APIの性能向上を多数盛り込んでいる。

J2SE 1.4

サン・マイクロシステムズが1.3から1.4での性能向上をまとめたリンクを参照

起動時間

Javaの起動時間は、膨大な数のクラス（プラットフォームのクラスライブラリの全てのクラスを含む）を使用前にロードしなければならないため、CやC++よりかなりかかることが多い。
起動時間の大半はJVMの初期化やクラスのロードそのものではなく、I/Oを伴う操作によるものと思われる (rt.jarのクラスデータファイルは40MBあり、JVMは多数のデータをこの巨大なファイルをシークして取り出さなければならない)。いくつかの実験により、バイトコード検証分割の方法を用いるとクラスのロードは約40%向上するが、大規模なプログラムの起動時間は5%しか向上しないことがわかった。
改善幅は小さいものの、単純な操作を実行しすぐ終了するような小さなプログラムでは、Javaプラットフォームのデータローディングはプログラムの操作の数倍の負荷であるため、向上が目に見えやすい。
Java SE 6 Update 10より、オラクルのJREにはQuick Starterが同梱されるようになり、OSの起動時にクラスのデータをロードしておくことで、ディスクではなくディスクキャッシュからデータを読み出すことができるようになる。
Excelsior JETでは、この問題に対して別の方向からアプローチしている。JETのStartup Optimizerはアプリケーションの起動時にディスクから読み出すデータを削減し、さらにシーケンシャルに読み出せるよう配置する。

三角関数

Javaの三角関数の性能は、Cと比べて悪い。Javaが数値演算の結果に（使用するハードウェアとも合致しない場合もある）厳密な仕様を定義しているためである。
x87での絶対値/4以上の値に対するサイン、コサインの演算結果は、の値に近似値を用いるため正確ではない。JVMの実装ではソフトウェアで正確な演算を行わなければならず、その領域では大きな性能低下を引き起こす。

Java Native Interface

Java Native Interfaceはオーバーヘッドが大きく、JVM上で動作するコードとネイティブコードの境界を行き来するコストが高くなっている。

ユーザインタフェース

Swingはウィジェットの描画をPure Javaで記述されたJava 2D APIに任せているため、ネイティブのウィジェット・ツールキットと比較して低速であるとされてきた。しかし、SwingとOSのネイティブGUIライブラリに描画処理を任せるStandard Widget Toolkitをベンチマークで比較しても、片方が明確に速いわけではなく、結果はコンテキストや環境に大きく依存した。

高性能計算分野での Java の使用

いくつかの独立した研究によれば、高性能計算 (HPC) における Javaの性能は、演算中心のベンチマークでFORTRANと同等であるが、JVMはグリッドネットワーク上の通信が多くなると、スケーラビリティに問題があるようである。
しかし、Javaで記述された高性能計算のアプリケーションがベンチマークで最高の成績を出したことがある。2008年、Javaで記述されたHPCのプロジェクト Apache Hadoop が、テラバイト級の整数のソートで最高速の結果を出した。