Java仮想マシンとCLR
-
19-08-2019 - |
質問
MSILとJavaバイトコードの違いと呼ばれる質問へのフォローアップとして? 、Java仮想マシンの動作と .NET Framework 共通言語ランタイム(CLR)の動作の(主な)違いまたは類似点は何ですか?
また、 .NETフレームワーク CLRは<!> quot;仮想マシン<!> quot;です。または、仮想マシンの属性がありませんか?
解決
両方の実装には多くの類似点があります(私の意見では、はい、両方とも<!> quot; virtual machines <!> quot;です)。
1つには、これらは両方ともスタックベースのVMであり、<!> quot; registers <!> quot;という概念はありません。 x86やPowerPCのような最新のCPUで見ることに慣れているように。すべての式((1 + 1)/ 2)の評価は、オペランドを<!> quot; stack <!> quot;にプッシュすることにより実行されます。そして、命令(加算、除算など)がそれらのオペランドを消費する必要があるときはいつでも、それらのオペランドをスタックからポップします。各命令は結果をスタックにプッシュします。
仮想マシンを実装するのに便利な方法は、世界中のほとんどすべてのCPUにスタックがありますが、レジスタの数は異なることが多いためです(また、一部のレジスタは専用であり、各命令は異なるオペランドを想定しています)レジスタなど)。
したがって、抽象的なマシンをモデル化する場合は、純粋にスタックベースのモデルを使用することをお勧めします。
もちろん、実際のマシンはそのようには動作しません。そのため、JITコンパイラーは<!> quot; enregistration <!> quot;を実行します。可能な場合は常に、オペランドと結果が含まれるように実際のCPUレジスタをスケジュールします。
だから、それはCLRとJVMの最大の共通点の1つだと思います。
違いについて...
2つの実装の興味深い違いの1つは、CLRにジェネリック型を作成し、それらの型にパラメトリック特殊化を適用するための命令が含まれていることです。そのため、実行時に、CLRはList <!> lt; int <!> gt;を考慮します。 List <!> lt; String <!> gt;とはまったく異なる型になります。
カバーの下では、すべての参照型の特殊化に同じMSILを使用します(したがって、List <!> lt; String <!> gt;はList <!> lt; Object <!> gtと同じ実装を使用します;、API境界で異なる型キャストを使用)、ただし、各値型は独自の一意の実装を使用します(List <!> lt; int <!> gt;は、List <!> lt; double <!とはまったく異なるコードを生成します> gt;)。
Javaでは、ジェネリック型は純粋にコンパイラのトリックです。 JVMには、どのクラスに型引数があるかという概念がなく、実行時にパラメトリックな専門化を実行できません。
実用的な観点からは、ジェネリック型でJavaメソッドをオーバーロードできないことを意味します。 List <!> lt; String <!> gt;を受け入れるかどうかだけが異なる、同じ名前の2つの異なるメソッドを持つことはできません。またはList <!> lt; Date <!> gt;。もちろん、CLRはパラメトリック型を知っているため、ジェネリック型の特殊化でオーバーロードされたメソッドの処理に問題はありません。
日常的に、それがCLRと JVM。
その他の重要な違いは次のとおりです。
-
CLRにはクロージャーがあります(C#デリゲートとして実装されます)。 JVMはJava 8以降のクロージャーのみをサポートします。
-
CLRにはコルーチンがあります(C#の 'yield'キーワードで実装されます)。 JVMはサポートしていません。
-
CLRでは、ユーザーコードで新しい値型(構造体)を定義できますが、JVMでは、値型(byte、short、int、long、float、double、char、boolean)の固定コレクションを提供し、ユーザーは新しい参照タイプ(クラス)を定義します。
-
CLRは、ポインターの宣言と操作のサポートを提供します。 JVMとCLRの両方がメモリ管理戦略として厳密な世代別圧縮ガベージコレクター実装を採用しているため、これは特に興味深いものです。通常の状況では、厳密な圧縮GCはポインターを使用するのが非常に困難です。これは、あるメモリー位置から別のメモリー位置に値を移動すると、すべてのポインター(およびポインターへのポインター)が無効になるためです。しかし、CLRは<!> quot; pinning <!> quot;を提供します。開発者がCLRが特定のポインターを移動することを許可されていないコードのブロックを宣言できるようにするメカニズム。とても便利ですnt。
-
JVMのコードの最大単位は、「protected」キーワードで示される「パッケージ」、またはクラスパスでjarを指定できることで示されるJAR(つまり、Java ARchive)です。コードのフォルダーのように扱われます。 CLRでは、クラスは「アセンブリ」に集約され、CLRはアセンブリ(<!> quot; AppDomains <!> quot;にロードされる)の推論と操作のロジックを提供し、メモリ割り当て用のサブアプリケーションレベルのサンドボックスを提供しますおよびコード実行)。
-
CLRバイトコード形式(MSIL命令とメタデータで構成される)の命令タイプは、JVMよりも少ないです。 JVMでは、一意の操作(2つのint値の追加、2つのfloat値の追加など)ごとに独自の一意の命令があります。 CLRでは、すべてのMSIL命令は多態性(2つの値を追加)であり、JITコンパイラーはオペランドのタイプを決定し、適切なマシンコードを作成します。ただし、どの戦略が望ましいかはわかりません。どちらにもトレードオフがあります。 JVM用のHotSpot JITコンパイラは、より単純なコード生成メカニズムを使用できます(オペランドタイプは既に命令でエンコードされているため、オペランドタイプを決定する必要はありません)が、より複雑なバイトコード形式が必要です。より多くの命令タイプがあります。
私は約10年間、Javaを使用しています(そしてJVMを賞賛しています)。
しかし、私の意見では、CLRはほぼすべての点で優れた実装です。
他のヒント
最初の質問は、JVMと.NET Frameworkの比較です。実際には、代わりにCLRと比較するつもりだったと思います。もしそうなら、この上に小さな本を書くことができると思います(編集:はベンジーがすでに持っているように見えます:-)
重要な違いの1つは、CLRがJVMとは異なり、言語に依存しないアーキテクチャとして設計されていることです。
別の重要な違いは、CLRがネイティブコードとの高いレベルの相互運用性を可能にするように特別に設計されていることです。これは、ネイティブメモリがアクセスおよび変更されたときにCLRが信頼性とセキュリティを管理する必要があることを意味します。また、 CLRベースのデータ構造とネイティブデータ構造間のマーシャリングの管理。
2番目の質問に答えるために、用語<!>#8220; virtual machine <!>#8221;は、ハードウェアの世界からの古い用語(1960年代のIBMの360度の仮想化など)で、VMWareと同じ種類の処理を行うために、基になるマシンのソフトウェア/ハードウェアエミュレーションを意味していました。
CLRはしばしば<!> quot;実行エンジン<!> quot;と呼ばれます。これに関連して、それはx86上でのILマシンの実装です。これはJVMの機能でもありますが、CLRの多態性バイトコードとJVMの型付きバイトコードには重要な違いがあると主張できます。
したがって、2番目の質問に対する舌な答えは<!> quot; no <!> quot;です。しかし、実際には、これら2つの用語をどのように定義するかにかかっています。
編集: JVMとCLRのもう1つの違いは、JVM(バージョン6)が非常に消極的で、割り当てられたメモリをオペレーティングシステムに解放します(可能な場合でも)。
たとえば、最初にJVMプロセスが起動し、オペレーティングシステムから25 MBのメモリを割り当てたとします。アプリコードは、さらに50 MBを必要とする割り当てを試みます。 JVMは、オペレーティングシステムからさらに50 MBを割り当てます。アプリケーションコードがそのメモリの使用を停止すると、ガベージコレクションされ、JVMヒープサイズが減少します。ただし、JVMは特定の特定の状況でのみ、割り当てられたオペレーティングシステムメモリを解放します>。それ以外の場合、プロセスの残りの期間、そのメモリは割り当てられたままになります。
一方、CLRは、割り当てられたメモリが不要になった場合、オペレーティングシステムに解放します。上記の例では、ヒープが減少すると、CLRはメモリを解放します。相違点に関する詳細は、さまざまな学術および民間の情報源から入手できます。良い例は、 CLR設計の選択です。
特定の例には次のものがあります。
- <!> quot; add int <!> quot;などの低レベルのオペランドがいくつか入力されます。 CLRは多相オペランドを使用します。 (つまり、fadd / iadd / ladd対単に追加)
- 現在、JVMはより積極的なランタイムプロファイリングと最適化を行います(ホットスポットなど)。現在、CLRはJIT最適化を実行しますが、実行時最適化は実行しません(実行中にコードを置き換えます)。
- CLRは仮想メソッドをインライン化しませんが、JVMはインライン化します...
- CLRでの<!> quot; primitives <!> quot;以外の値型のサポート。
CLRとJVMは両方とも仮想マシンです。
.NET FrameworkとJavaランタイム環境は、それぞれのVMとそのライブラリのバンドルです。ライブラリがなければ、VMはまったく役に立ちません。
仮想マシンではありません。.netフレームワークは、最初の実行時にアセンブリをネイティブバイナリにコンパイルします。
コンピューティングでは、動的翻訳とも呼ばれるジャストインタイムコンパイル(JIT)は、コンピュータープログラムの実行時のパフォーマンスを向上させる手法です。 JITは、ランタイム環境での2つの初期のアイデア、バイトコードコンパイルと動的コンパイルに基づいています。ネイティブに実行する前に実行時にコードを変換します。たとえば、バイトコードをネイティブマシンコードに変換します。インタープリターよりもパフォーマンスが向上するのは、コードブロックの変換結果をキャッシュすることであり、各行またはオペランドが満たされるたびに単純に再評価することではありません(解釈言語を参照)。また、開発時にコードを静的にコンパイルするよりも利点があります。これは、有利であることがわかった場合にコードを再コンパイルでき、セキュリティ保証を実施できる可能性があるためです。したがって、JITは解釈と静的(事前)コンパイルの利点のいくつかを組み合わせることができます。
Microsoftの.NET Framework、Javaのほとんどの実装、最近のActionscript 3などのいくつかの最新のランタイム環境は、高速コード実行のためにJITコンパイルに依存しています。
出典: http://en.wikipedia.org/wiki/Just-in -time_compilation
.NETフレームワークを追加すると、Javaと同様に仮想マシンが含まれます。