なぜ仮想マシンが必要なのですか?


8

それぞれのOS(ターゲットとなっているOS)のソースコードをコンパイルする代わりに、一度コンパイルしてどこでも実行できます。

この質問のために、私はそれをVMと呼びます(たとえば、Javaと.NETの両方)。したがって、プログラムの実行は次のようになります

 ------------       ----      ----
| Executable |  -> | VM | -> | OS |
 ------------       ----      ----

それは完全に理にかなっています、コンパイラはそれぞれのVMのために汎用のままです。ただし、VMの実装は、インストールするマシンによって異なります(* nix、windows、mac)x(32ビット、64ビット)。

私の質問は、それぞれのマシン用にVMを作成する代わりに、なぜその特定のマシン用にコンパイラーが作成されないのですか?これにより、それぞれのVMをダウンロードする代わりに、それぞれのコンパイラをダウンロードすると、そのコンパイラがその特定のマシンのmachine-code + OSを処理します。最終的には、あらゆるマシンのネイティブコードの実行。確かに、各ソースコードはその特定のマシン用にコンパイルする必要がありますが、今日では、自動化されたシステムであるscmビルドがこの作業に役立ちます。

混乱している私の理由は正しいですか、またはここでいくつかの専門知識が不足していますか?

編集:

ポータビリティ

はい、それは1つの理由ですが、今日の自動化システムでは移植性が大きな問題ですか?他のマシン用にコンパイルする必要がないという事実をどれくらいの頻度で心配する必要がありますか?ネイティブマシン用にコンパイルされたコードを使用すると、パフォーマンスが大幅に向上します。Javaを例にとると、Windowsで低レベルのプログラミングを行うことはできず、JNIを選択する必要があります。

TeamCity / Jenkinsなどの自動化システムを利用してください。バージョン管理を介して送信されたコードが実行可能ファイルになるような自動化されたシステムセットアップを使用できます。


5
あなたは最初の段落であなた自身の質問に答えました
ラチェットフリーク

6
Javaでは新しいことはありません。UCSD Pascal(1つの例のみ)も同じことを行いました。
Jerry Coffin

2
@EmAeそして、JVMで実行される2つのCIビルドシステムを選択したという皮肉を指摘します。
アンドリューTフィネル

1
「それぞれのVMをダウンロードする代わりに、それぞれのコンパイラーをダウンロードすると、そのコンパイラーがその特定のマシンのmachine-code + OSを処理します」 -これがCと呼ばれています。これは、Linuxでのソフトウェアの配布方法の本質です。たとえば(パッケージマネージャーの前)。申し訳ありませんが、閉じるには投票する必要があります。
GrandmasterB

すべてのコンパイラには、一連の仮想マシンが含まれています。ある時点でコンパイルを停止し、その中間表現をシリアル化してから、残りのコンパイラを「仮想マシンインタープリタ」と呼ぶことができます。何も変わりません。
SK-logic

回答:


16

私の質問は、それぞれのマシン用にVMを作成する代わりに、なぜその特定のマシン用にコンパイラーを作成しないのですか?

そのため、ポータブルな実行可能ファイルはもうありません。プラットフォームごとに1つの実行可能ファイルがあります。ユーザーは、プラットフォーム用の特定の実行可能ファイルをダウンロードするか、特定のプラットフォームでコードをコンパイルする必要があります。

VMを使用すると、各プラットフォームでプラットフォーム固有のVMが必要になるだけで、同じ実行可能ファイルをすべてのプラットフォームに配布できます。


2
今日のVMは、あなたが信用するよりもパフォーマンスが優れています。VMを使用すると、タイプシステム、ライブラリフレームワーク、ガベージコレクションなどの管理されたすべての機能を無料で利用できます。
ロバートハーベイ、

3
@ロバート:すべてのネイティブコードがCまたはC ++であるとは限らないことに注意してください。それらはネイティブであり、したがって「多くの低レベルの複雑さで対処する」ため、プログラムの作成に時間がかかることはありません。それらは低レベルのものをうまく処理しない設計が不十分な言語であるため、プログラムを書くのが遅いです。しかし、マネージ言語で見られるのと同じ開発の容易さでDelphiからCレベルのパフォーマンスを引き出すことができます。
メイソンウィーラー、

7
@Andrew:孤立したケースでアルゴリズムをテストするベンチマークによれば、Javaは高速であると人々は言うことができます。しかし、実際にOpenOfficeなどの実際のJavaプログラムを実行すると、ネイティブコードでの約1〜2秒に比べて、おかしな保存ダイアログを開くのに30秒かかります。ベンチマークは何も意味しません。Javaはまだ遅いです。
メイソンウィーラー

2
@MasonWheelerあなたがあなたのコメントを削除して、新しいものに拡大したとき。CおよびC ++へのエントリの障壁は非常に高く、プログラムが本当に悪いため、Java言語での「プログラミング」を回避できる人の数は非常に多くなります。Javaは遅いわけではなく、恐ろしいアプリケーションスイートの事例証拠が他に証明されていません。
アンドリューTフィネル

10
@MasonWheeler:よくある誤解を解消するために:OpenOfficeはJavaで書かれておらず、主にC ++で書かれています。いくつかの特別な機能にはJavaが必要です。wiki.services.openoffice.org/wiki/Java_and_OpenOffice.orgを参照してください。
sleske 2012

12

これらのVMを使用すると、巨大なものが不足しています。彼らはあなたが言うことを正確に行いますが、自動的に行います。これはJust-In-Timeコンパイラと呼ばれ、.NET(Windowsの場合)とJavaがネイティブにコンパイルされたC ++コードの速度に非常に近い理由です。

Java / C#ソースコードはバイトコードに変換されます。このバイトコードは、現在実行されているマシンのマシンコードにコンパイルされます。ほとんどの場合、VMはバイトコードを再処理する代わりにネイティブコードを実行します。

私はかなりスキップしてプロセスを単純化しすぎましたが、VMはかなりの量の作業を行います。


あなたは私の質問を受け取っていません。特定のVMで実行されているときのコードのパフォーマンスに疑いはありません。問題は、特定のマシン用にそれをコンパイルするコンパイラーがある場合に、なぜVMを使用するかです。
Em Ae

2
@EmAe VMは特定のマシン用にコンパイルします。これはJITと呼ばれます。よく読んでおくことを強くお勧めします。
Andrew T Finnell、

1
わかりました、私はここで混乱しています。私を訂正して助けてください。では、コンパイラは特定のマシン用にコンパイルされますが、VMで実行するように選択されていますか?コンパイルされたコード(たとえば、JAVAと言います)がUNIX / Mac / Ubuntu上のVMに移植される場合、これを再コンパイルする必要がありますか?番号。VMの場合、ネイティブはBYTE-CODEであり、そのBYTE-CODEはJITを使用して変換されるためです。Program -> Compiled to byte code -> JIT for machine -> Execution。4つのステップが含まれます。なぜこれらの4つのステップを使用するのですか?その後、私たちはできるProgram -> Machine specific compiler -> Execute
Em Ae、

アセンブリですべてのコードを何度も書き換えないのと同じ理由です。再利用。
アンドリューTフィネル

2
さらに、これらの4つのステップを実行する必要があると誰も言いません。いつでもAOTコンパイラーを使用できます。gcc.gnu.org/java
TomJ

7

コンピューターサイエンスの多くの概念と同様に、VMは抽象化レイヤーを提供します。インターフェース(バイトコード/中間言語)に対してコードを記述し、抽象化レイヤー(VM)が実装の詳細(ターゲットマシン用のコンパイル、およびその他のタスク)を処理します。抽象化レイヤーはセットを提供します実装の詳細が不要になったサービスの一覧。この場合、抽象化レイヤーサービス(VM)が存在するので、基盤となるハードウェアの詳細について心配する必要はありません。クライアントは同様の方法でメリットを得ます-抽象化レイヤーを使用できるというだけで、プラットフォームに関する詳細を知る必要はありません。

もちろん、抽象化にはトレードオフがあります。抽象化の反対側の細部をきめ細かく制御できなくなり、その抽象化に頼って賢明な実装を採用する必要があります。トレードオフに対する抽象化を使用して、潜在的な利益を検討する必要があります。特定のアプリケーションでは、欠点がメリットを上回る可能性があります。プラットフォームごとに、その高レベルの制御が必要になる場合があります。

異なるプラットフォームへのコンパイルに自動化システムを使用するというあなたの提案は、まさに.NETおよびJava抽象化レイヤーがすでに行っていることです。JITコンパイルの利点の1つは、コンパイラーが実行されているマシンに関する特定の詳細をコンパイラーが持っていることです。これにより、開発者のマシンでリリースビルドを実行する場合には不可能であった最適化の可能性が生まれます。

ネイティブコードの生成とプログラムの実行が同時に発生するために実行速度が低下することが懸念される場合は、プログラムを最初に実行するときではなく、インストール中にネイティブコードを生成するオプションがあります。.NETはこの目的のためにnGenを提供し、実行時ではなくインストール時にネイティブコード生成を実行できます。CLRは、JITコンパイルを実行するのではなく、キャッシュされたネイティブコードを使用します。


3

これは非常に単純化しすぎています。クロスプラットフォームは、特定のネイティブ命令セット用にコンパイルするだけではありません。APIとライブラリが異なるため、同じC / C ++コードを異なるプラットフォームで単に再コンパイルすることはできません。たとえば、GUI開発はWindowsとUbuntu Linuxでは大きく異なり、ソケット通信はおそらくUnixとIBM z / OSでは同じではありません。

したがって、「一度だけ書き込み、どこでもコンパイル(およびリンク)」するには、すべてのOSレベルのサービスに共通のAPIを作成する、ある種の抽象化レイヤーを作成する必要があります。次に、これを実装して、サポートするすべてのプラットフォームに配布する必要があります。

また、今日のメモリモデルはますます類似していますが、異なるプラットフォームの間には依然としていくつかの違いがあるため、メモリ割り当ても抽象化する必要があります。ここで最も簡単なのは、ネイティブのメモリマネージャの上に独自の「仮想」メモリマネージャを作成することです。

その間、ファイルシステムとアクセス制御(ACL)は、たとえば、UnixとWindowsでかなり異なる方法で処理されるため、それらも抽象化する必要があります。おそらく、基礎となる実装用に独自の「ファイル」ラッパーを作成することもできます。

次に、スレッド化します。Linuxにはプロセスしかなく、Windowsにはスレッドがあるので、これも何らかの形で抽象化する必要があります。

さて、この時点で仮想マシンはほぼ構築されました。ここでの要点は、異なるプラットフォーム用に任意のコードコンパイルするのはかなり簡単ですが、どのプラットフォームでも実行できる複雑さのある作業用ソフトウェア構築することは簡単なことではありません。


2

VM / JITアプローチのもう1つの大きな利点は、バイナリ互換性です。たとえば、クラスAを含むアセンブリ/ JAR / DLLと、クラスAから派生するクラスBを含む別のアセンブリがあるとします。プライベートメンバーを追加するなど、クラスAを変更するとどうなりますか?プライベートメンバーを追加してもクラスBにはまったく影響がありませんが、Bを含むアセンブリが既にネイティブコードにコンパイルされている場合、ネイティブコードが次のようにコンパイルされているため、奇妙なバグが発生し、再現が困難になります。 Aの古いメモリレイアウト。たとえば、Aの変数用に予約するメモリが少なすぎるため、Aのメンバーと追加されたメンバーBは同じメモリ位置にマップされます。

一方、VMを使用している場合、コードがネイティブコードにコンパイルされると、すべてのクラスのレイアウトがわかるため、これらの問題はすべてなくなります。


2

私の質問は、それぞれのマシン用にVMを作成する代わりに、なぜその特定のマシン用にコンパイラーを作成しないのですか?

これが動作する方法であると少し想像してみましょう。私はJavaアプリケーションを作成し、それをコンパイルします。コンパイラーは、サポートされているすべてのプラットフォームの実行可能ファイルを生成します。現在、次の実行可能ファイルがあります。

  • Solaris x64
  • Solaris x86
  • Solaris SPARC
  • Windows x86
  • Windows x64
  • Linux x86
  • Linux x64
  • マックOS
  • BSD

などなど

次に、これらすべてを自分のWebサイトにアップロードし、それぞれにダウンロードリンクを提供します。次に、これらすべてをdownload.com、tucows.com、sofpedia.comに送信し、それぞれを個別に送信します。

これは私にとって大きな痛みのようです!ソフトウェアをバージョン1.1に更新したら、このプロセスを繰り返す必要があります。

そして、新しいプラットフォームが出現するとどうなりますか?現在、私のソフトウェアはこのプラットフォームで利用できません。開発者ソフトウェアを更新してサポートしない限り、再コンパイルしてから、この新しいプラットフォーム用にソフトウェアを再リリースします。

そして、ユーザーはどうですか?彼らは私のサイトにアクセスし、プラットフォームから使用するソフトウェアの正確なバージョンをリストから選択する必要があります。ほとんどのユーザーはx86またはx64のどちらを実行しているかわからないため、おそらく間違ったバージョンをダウンロードして何らかのエラーを受け取ることになります。その後、WindowsからMacに切り替えた場合、戻ってソフトウェアを再ダウンロードする必要があります。

これはすべて、開発者とユーザーの両方にとって大きな痛みであり、Javaが現在行っているのとまったく同じように、バイトコードにコンパイルしてVMで実行するだけで、これらすべてを回避できます。

パフォーマンスがネイティブコードの実行とほぼ同じである場合、問題は、なぜネイティブコードにコンパイルしないのかではなく、なぜわざわざネイティブコードにコンパイルするのかということです。


1

あなたの投稿の編集では、移植性、VMについての有用性に疑問があります。

私のプロ生活の中で、移植性がされている最も重要な要因-マイ展開プラットフォームは非常に稀に私が展開することを同じプラットフォームではない、と私はWindows上で&テストを開発することができていますので、Linux上でテストするだろう誰が、私のQAのDEPTに渡します、Solarisの本番環境にデプロイします。

これは、単に孤立して考案された例だけではありません。これは、おそらく私の過去数十年のキャリアの12年間、私の専門家としての存在の大部分を占めてきました。同じまたは同様の経験を持つ他の多くがいると確信しています。

(同じソースコードで)異なる(クロス)コンパイラーを使用して異なるバイナリーを生成した場合、それぞれが独自のOS /アーキテクチャーでテストされていないと、各バイナリーの品質に自信が持てません。

すばらしいオープンソースのFreePascalコンパイラプロジェクトには、「一度だけ書き込み、どこでもコンパイルする」というタグラインがあります。これは事実ですが、評判の良いソフトウェア会社がそうし、すべてのプラットフォームで徹底的にテストせずにアプリケーションをリリースすることは期待できません。


VMを使用している場合でも、1つのプラットフォームでのテストと別のプラットフォームへの展開の妥当性については疑問を呈します。2つの異なるVM実装にデプロイしています。一方には、もう一方には存在しないシステム固有のバグが含まれている可能性があります。可能性はわずかですが、同一のシステムでテストして展開することは依然として良い習慣です。
Gavin Coates

TBH、私は実際に同意しますが、コンパイラよりVMをテストする方が簡単ですか?(つまり、テストが簡単なため、VMの信頼性は高いですか、それとも同じくらい危険ですか?)少なくともVMを使用すると、コードは何千(何百万?)ほんの一握り)があなたのアプリケーションをコンパイルしました。
Crollster 2012

Crollster:同意します。現実の世界では、同じハードウェアとソフトウェアを使用しますが、これができない場合もあります。ほとんどの場合、別のプラットフォームを使用しても問題ありませんが、比較的小さいものの、エラーのリスクがあることを覚えておいてください。
Gavin Coates

1

簡単:テスト。

コードが仮想マシンで正常に機能する場合、VMが機能していることが証明されている他のハードウェアでコードが実行されると確信できます。

異なるプラットフォーム用にコンパイルする場合は、すべてのプラットフォームに独自の癖があるため、多くのテストを行う必要があります。


0

コードをコンパイルできることだけでなく、移植性よりも優れています!

Cプログラムの動作は、プラットフォームによって異なる場合があります。

int  i;
char c[6];
int * p;

p = &c[2];
p = p + 1;

IBM Powerチップでは問題なく動作しますが、SPARCチップでは例外が発生します。

OS、OSバージョン、ファイルシステム環境変数のレジストリ設定はすべて、コンパイルされたプログラムの実行方法に影響を与える可能性があります。

JVMは、ハードウェアとソフトウェアの環境に関係なく、同じ動作をほぼ保証します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.