CLR と JVM には、想像以上に異なる目標と哲学があります。一般に、JVM はより動的で高レベルのコードを最適化することを目的としていますが、CLR は、この種の最適化を自分で行うための低レベルのツールを提供します。
良い例は、スタック割り当てです。CLR では、カスタム値型の明示的なスタック割り当てがあります。JVM では、唯一のカスタム型は参照型ですが、JVM は特定の状況で Escape Analysis を介してヒープ割り当てをスタック割り当てに変換できます。
もう一つの例。Java では、メソッドはデフォルトで仮想です。少なくとも C# では、そうではありません。特定の呼び出しサイトで実行されるコードは静的に決定できないため、仮想メソッド呼び出しを最適化することははるかに困難です。
内部では、それらの実行システムはまったく異なります。ほとんどの JVM (特に Hotspot) はバイトコード インタープリターから開始し、タイトなループなど、頻繁に実行されるコードの部分のみを JIT コンパイルします。また、以前の実行から収集された実行統計を使用して、これらを何度も再コンパイルして最適化を促進することもできます。これにより、最適化を最も必要とするプログラムの部分により多くの最適化作業を適用できます。これは適応最適化と呼ばれます。
CLR は、事前にすべてを 1 回だけコンパイルします。コンパイルするコードが多いため高速である必要があるため、また最適化にフィードするために使用される実際の実行パスの統計がないため、最適化が少なくなります。このアプローチには、プロセス間でコンパイル結果をキャッシュできるという非常に大きな利点があります。これは、CLR にはありますが、JVM にはありません。
Hotspot JVM コードの大部分は、これらの適応最適化に専念しており、2000 年代初頭のほとんどの汎用計算において Java をネイティブ コードと同じパフォーマンスの球場に置いたのはこのためです。それらはまた、JVM を動的言語のまともなターゲットにするものでもあります。DLR について十分な知識がないため、ここでは動的言語ランタイムと invokedynamic の最近の開発を除外しています。