web-dev-qa-db-ja.com

Java仮想マシンとCLR

MSILとJavaバイトコードの違い と呼ばれる質問へのフォローアップのようなものとして、Java仮想マシンの動作と方法 。ネットフレームワーク 共通言語ランタイム(CLR)は機能しますか?

また、 。ネットフレームワーク CLRは「仮想マシン」ですか、それとも仮想マシンの属性がありませんか?

135
Frank V

両方の実装には多くの類似点があります(私の意見では、はい、どちらも「仮想マシン」です)。

1つには、両方ともスタックベースのVMであり、x86やPowerPCなどの最新のCPUで見られるような「レジスタ」の概念はありません。すべての式((1 + 1)/ 2)の評価は、オペランドを「スタック」にプッシュし、命令(加算、除算など)がそれらのオペランドを消費する必要があるたびに、それらのオペランドをスタックからポップすることによって実行されます。各命令は、結果をスタックにプッシュします。

世界中のほぼすべてのCPUにスタックがあるため、仮想マシンを実装するのに便利な方法ですが、レジスタの数は異なることがよくあります(そして、一部のレジスタは特殊用途であり、各命令は異なるレジスタにオペランドを期待します) )。

したがって、抽象的なマシンをモデル化する場合は、純粋にスタックベースのモデルを使用することをお勧めします。

もちろん、実際のマシンはそのようには動作しません。そのため、JITコンパイラはバイトコード操作の「登録」を実行し、可能な場合は常にオペランドと結果を含むように実際のCPUレジスタをスケジューリングします。

ですから、それはCLRとJVMの最大の共通点の1つだと思います。

違いは...

2つの実装の興味深い違いの1つは、CLRにジェネリック型を作成し、次にそれらの型にパラメトリック特殊化を適用するための命令が含まれていることです。そのため、実行時に、CLRはList <int>をList <String>とはまったく異なる型と見なします。

カバーの下では、すべての参照型の特殊化に同じMSILを使用します(したがって、List <String>は、API境界で異なる型キャストを持つList <Object>と同じ実装を使用します)が、各値型は独自の実装(List <int>はList <double>とはまったく異なるコードを生成します)。

Javaでは、ジェネリック型は純粋にコンパイラのトリックです。 JVMには、どのクラスに型引数があるかという概念がなく、実行時にパラメトリックな特殊化を実行できません。

実用的な観点から、それはJavaジェネリック型のメソッドをオーバーロードできないことを意味します。リストを受け入れるかどうかだけが異なる、同じ名前の2つの異なるメソッドを持つことはできません。 String>またはList <Date>。もちろん、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は「固定」メカニズムを提供するため、開発者はCLRが特定のポインターを移動することを許可されていないコードブロックを宣言できます。とても便利です。

  • JVMのコードの最大単位は、「protected」キーワードで示される「パッケージ」、またはjarを指定できることで示されるJAR(つまりJava ARchive))です。 CLRでは、クラスは「アセンブリ」に集約され、CLRはアセンブリ(「AppDomains」にロードされ、サブアプリケーションレベルを提供する)の推論と操作のためのロジックを提供します。メモリ割り当てとコード実行のためのサンドボックス)。

  • CLRバイトコード形式(MSIL命令とメタデータで構成されている)の命令タイプは、JVMよりも少ないです。 JVMでは、一意の操作(2つのint値の追加、2つのfloat値の追加など)ごとに独自の一意の命令があります。 CLRでは、すべてのMSIL命令は多態的(2つの値を追加)であり、JITコンパイラーはオペランドのタイプを決定し、適切なマシンコードを作成します。ただし、どの戦略が望ましいかはわかりません。どちらにもトレードオフがあります。 JVM用のHotSpot JITコンパイラは、よりシンプルなコード生成メカニズムを使用できます(オペランドタイプは既に命令でエンコードされているため、オペランドタイプを決定する必要はありません)。ただし、より複雑なバイトコードフォーマットが必要です。より多くの命令タイプがあります。

私は約10年間、Java(およびJVMを称賛)を使用しています。

しかし、私の意見では、CLRはほぼすべての点で優れた実装です。

272
benjismith

最初の質問は、JVMと.NET Frameworkの比較です。実際には、代わりにCLRと比較するつもりだったと思います。もしそうなら、この上に小さな本を書くことができると思います(EDIT:はベンジーがすでに持っているように見えます:-)

重要な違いの1つは、CLRがJVMとは異なり、言語に依存しないアーキテクチャになるように設計されていることです。

もう1つの重要な違いは、CLRがネイティブコードとの高レベルの相互運用性を可能にするように特別に設計されていることです。つまり、CLRは、ネイティブメモリがアクセスおよび変更されたときに信頼性とセキュリティを管理する必要があり、CLRベースのデータ構造とネイティブデータ構造の間で マーシャリングを管理 する必要があります。

2番目の質問に答える場合、「仮想マシン」という用語はハードウェアの世界からの古い用語(1960年代のIBMの360の仮想化など)であり、同じようなことを達成するための基礎となるマシンのソフトウェア/ハードウェアエミュレーションを意味していましたVMWareが行うこと。

CLRはしばしば「実行エンジン」と呼ばれます。これに関連して、それはx86上でのILマシンの実装です。これもJVMの機能です。ただし、CLRのポリモーフィックバイトコードとJVMの型付きバイトコードには重要な違いがあると主張できます。

したがって、2番目の質問に対するquestion舌な答えは「いいえ」です。しかし、実際には、これら2つの用語をどのように定義するかにかかっています。

EDIT:JVMとCLRのもう1つの違いは、JVM(バージョン6)が 非常に消極的 割り当てられた解放可能な場合でも、オペレーティングシステムにメモリを戻します。

たとえば、JVMプロセスが起動し、オペレーティングシステムから最初に25 MBのメモリを割り当てたとします。アプリコードは、さらに50 MBを必要とする割り当てを試みます。 JVMは、オペレーティングシステムからさらに50 MBを割り当てます。アプリケーションコードがそのメモリの使用を停止すると、ガベージコレクションされ、JVMヒープサイズが減少します。ただし、JVMは特定の 非常に特殊な状況 の場合にのみ、割り当てられたオペレーティングシステムメモリを解放します。それ以外の場合、残りのプロセスライフタイムの間、そのメモリは割り当てられたままになります。

一方、CLRは、割り当てられたメモリが不要になった場合、オペレーティングシステムに解放します。上記の例では、ヒープが減少すると、CLRはメモリを解放します。

25
RoadWarrior

相違点に関する詳細は、さまざまな学術および民間の情報源から入手できます。良い例は、 CLR Design Choices です。

いくつかの具体的な例は次のとおりです。

  • CLRが多態性オペランドを使用する「2つの整数を追加」など、一部の低レベルオペランドが入力されます。 (つまり、fadd/iadd/ladd対単に追加)
  • 現在、JVMはより積極的な実行時プロファイリングと最適化(つまり、ホットスポット)を実行します。現在、CLRはJIT最適化を実行しますが、実行時最適化は実行しません(実行中にコードを置き換えます)。
  • CLRは仮想メソッドをインライン化しませんが、JVMはインライン化します...
  • 「プリミティブ」以外のCLRでの値型のサポート。
11
James Schek

CLRとJVMは両方とも仮想マシンです。

.NET FrameworkとJava Runtime Environmentは、それぞれのVMとそのライブラリのバンドルです。ライブラリがなければ、VMはほとんど役に立ちません。

9
Allain Lalonde