Javaは、プログラムの移植性を可能にするために仮想マシンで実行するように設計されています。
ただし、.NETは最初からWindows専用に設計されています。
.NETアプリケーションがCLRのバイトコードにコンパイルされる理由は何ですか?
それは単にJavaをコピーすることでしたか?それともネイティブでコンパイルするだけの技術的な利点はありますか?
bytecode へのコンパイルは古い伝統です。 CSD P-コード は1978年に存在し、多くの前駆体がありました。今日、 [〜#〜] llvm [〜#〜] は、バイトコードとして見ることができ、 Clang/LLVM 先読みコンパイラスイートおよび [〜#〜] gccjit [〜#〜][〜#〜] gcc [〜#〜] に関連するJITとして表示できます [〜# 〜] gimple [〜#〜] 一部の内部バイトコード)の並べ替え。
(したがって、バイトコード、JIT、...は今日、かなりあいまいな意味を持っています。JITの最も広い意味は、コンパイルされたコードを実行するプロセス内のコンパイルです。)
JVMバイトコードは最初にインタプリタとして実装されました。しかし、Javaを取得するのに十分人気が出る [〜#〜] jit [〜#〜] ベースのJVM(そしてSunはJITテクノロジーに多くの投資をしたので、これはJava成功するために)。
そして、JITはずっと前から存在しており(1980年代初頭、たとえばLISPマシン、さらには1960年には CAB 5 コンピュータなどで)、名前が使用される前でさえありました。多くの一般的なLISPまたはSmalltalk実装にはJITコンパイラーがありました(そして、今日 [〜#〜] sbcl [〜#〜] は完全にJIT化されています)。
私の理解では、MicrosoftはCLRバイトコードをJITコンパイルするように設計しました(そのため、バイトコードでJVMとは異なるトレードオフが発生しました)。そして最近、その実装を オープンソースソフトウェア として公開し、それをLinuxに移植しました(それ以前は Mono はLinuxに存在していました)。
多くの場合、バイトコードはネイティブバイナリよりもコンパクトです 実行可能ファイル 。これは、いくつかのアーキテクチャ(たとえば、x86 32ビットおよびx86-64、さらにARM 32ビット、 ARM/Aarch64、...)および dependency hells を回避する(または少なくとも緩和する)ように設計されている可能性があります。
JITコンパイルの大きな利点は、VM canrecompilesomepartsof the bytecode) 動的コンテキスト情報に基づいて(たとえば、プロファイリング、 コールスタックイントロスペクション 、...)一部のコード。 libjitなどの一部のJITインフラストラクチャ 、 asmjit 、 [〜#〜] llvm [〜#〜] 、 [〜#〜] gccjit [〜#〜] 、...それをしないでください(ただし、それらを使用する実装では、JITインフラストラクチャを繰り返し使用することでそれを行うことができます)。動的コンパイルを要求します。私にとって、JITは実行時の動的コンパイルの単なる流行語です。これは AOTコンパイル では困難または不可能です(少なくとも [〜#〜] lto [〜が必要です) #〜] )、そして実行したい場合は不可能です プロファイルに基づく最適化 実行時に動的に(ほとんどのJVMまたはCLR JIT実装が実行していると噂されているため)。また、バイトコードVMすべてのバイトコードをJITコンパイルする必要はありません、bu ( HotSpot のように)最も使用頻度の高い部分のみを使用し、ほとんど使用されないコールドコードを解釈し続けます。
また、JIT実装は、洗練された ガベージコレクター とはるかに(そしてより良い...)連携できます。
PS。私はWindowsについて何も知りません。使ったことがない。私は1994年以来Linuxを、1987年以来Unixを使用しています。
Windowsは単一の同種のプラットフォームではありません。 clrの最初のバージョンがリリースされたとき、それは(x86でのみ動作する)従来のWindows 98ファミリーのシステムだけでなく、Windows NT 4(x86、ppc、alpha、mips)もターゲットにしていました。 Windows ce(x86、sh、arm、mips、ppcで実行された)のサポートはバージョン1.1で追加されましたが、ia64( "itanium")とntのx86-64ターゲットはバージョン2で追加されました。開発者は、プロジェクトの開始時にこれらのプラットフォームのほとんどまたはすべてをサポートする必要があることを知っていました。実際、ISVがこれほど多くのハードウェアプラットフォームをサポートすることに熱心ではなく、システムの開発を進めるというMicrosoftの決定にあると考えられたアプリケーションのx86バージョンのみをリリースする傾向があったという事実がありそうです。
Eric Lippertが、なぜ.NET言語がILをターゲットにするかについて、「 なぜILなのか 」というタイトルのバイナリファイルを直接生成するのではなく、適切な説明をしています。
その理由は、コンパイラを開発するコスト/労力が、このアプローチの方が安く/簡単だからです。高水準言語コンパイラは、共通の中間言語を生成します。これにより、コードを生成するプラットフォームが1つしかないため、新しい言語を簡単に追加できます。次に、この中間言語を使用してプラットフォーム固有のバイナリ(OSおよびCPUアーキテクチャ)を出力する2番目のステージコンパイラがあります。
このようにして、新しいプラットフォーム(新しいプロセッサなど)のサポートを追加するたびに、ILを新しいプラットフォームにコンパイルする単一のコンパイラを作成する必要があります。
.NET型システムの多くの機能、特に2.0で追加されたジェネリック型ですが(私が理解しているところによると)最初から想定されていたため、プログラムが使用する前にプログラムが使用する可能性のあるすべての型のコードをコンパイルすることは文字通り不可能になっています実行を開始します(プログラムが使用するタイプの組み合わせは、プログラムが受け取った入力によって任意の方法で影響を受ける可能性があるため、1回の実行中にプログラムが実際に使用する離散タイプの数は制限されますが、プログラムがさまざまな入力に応じて使用できるタイプの数は必要ありません)。動的コード生成は仮想マシンがなくても可能ですが、仮想マシンを使用すると、はるかに簡単かつ安全になります。
さらに、マルチスレッド環境でのガベージコレクションの効率は、ガベージコレクションされたオブジェクトへの参照を使用する可能性のあるすべてのスレッドを同時にブロックする機能をガベージコレクターに与えることにより、大幅に改善できます。ガベージコレクターが「stop-the-world」イベントを可能な限り短く保つ必要がある場合でも、コレクターが一方的に他のスレッドをGC参照と相互作用しないようにロックする機能により、他のスレッドが参照なしで参照を読み書きできるようになります。インターロックされた読み取りと書き込みを使用する必要があります。これは、効率に大きな影響を与える可能性があります。
.NET VMが管理するほとんどのことは、VMを使用しなくても実行できますが、VMを使用すると、安全性とパフォーマンスが大幅に向上し、欠点。