
コンピューティングにおいて、仮想マシン(VM)とは、コンピュータシステムの仮想化またはエミュレーションのことです。仮想マシンはコンピュータアーキテクチャに基づいており、物理コンピュータの機能を提供します。その実装には、専用のハードウェア、ソフトウェア、またはその両方の組み合わせが含まれる場合があります。仮想マシンは機能によって異なり、以下のように分類されます。
QEMUやビデオゲーム機エミュレータなど、一部の仮想マシンエミュレータは、異なるシステムアーキテクチャをエミュレート(または「仮想的に模倣」)するように設計されており、別のCPUやアーキテクチャ向けに作成されたソフトウェアアプリケーションやオペレーティングシステムを実行できます。OSレベルの仮想化では、カーネルを介してコンピュータのリソースを分割できます。これらの用語は必ずしも互換性があるわけではありません。
「仮想マシン」は、もともとポペックとゴールドバーグによって「実際のコンピュータマシンの効率的で隔離された複製」と定義されました。[ 2 ]現在の用法には、実際のハードウェアに直接対応しない仮想マシンも含まれます。[ 3 ] VM を実行する物理的な「現実世界」のハードウェアは一般的に「ホスト」と呼ばれ、そのマシン上でエミュレートされる仮想マシンは一般的に「ゲスト」と呼ばれます。1 つのホストは複数のゲストをエミュレートでき、それぞれのゲストは異なるオペレーティングシステムとハードウェア プラットフォームをエミュレートできます。
複数のオペレーティングシステムを実行したいという要望が、仮想マシンの最初の動機であり、複数のシングルタスクオペレーティングシステム間でタイムシェアリングを可能にするものでした。ある意味では、システム仮想マシンは、歴史的にそれより前に存在した仮想メモリの概念の一般化と考えることができます。完全な仮想化を可能にした最初のシステムであるIBMのCP/CMSは、各ユーザーにシングルユーザーオペレーティングシステムである会話モニタシステム(CMS)を提供することでタイムシェアリングを実現しました。仮想メモリとは異なり、システム仮想マシンでは、ユーザーはコード内に特権命令を記述することができました。このアプローチには、標準システムでは許可されていない入出力デバイスを追加できるなど、いくつかの利点がありました。[ 3 ]
仮想化の目的で仮想メモリの技術が進化するにつれて、1 つのコンピュータのオペレーティングシステム上で複数の仮想マシン間でメモリを共有するために、新しいメモリオーバーコミットシステムが適用される可能性があります。同じ物理マシン上で実行される複数の仮想マシン間で、同一の内容を持つメモリ ページを共有することが可能になり、カーネル同一ページマージ(KSM) と呼ばれる手法によって、それらを同じ物理ページにマッピングすることが可能になります。これは、コード セグメントを保持する読み取り専用ページなどに特に役立ちます。これは、同じまたは類似のソフトウェア、ソフトウェア ライブラリ、Web サーバー、ミドルウェアコンポーネントなどを実行する複数の仮想マシンの場合に該当します。ゲスト オペレーティングシステムはホスト ハードウェアに準拠する必要がないため、将来のソフトウェアをサポートするために、同じコンピュータ上で異なるオペレーティングシステム (たとえば、Windows、Linux、または以前のバージョンのオペレーティングシステム) を実行することが可能です。[ 4 ]
組み込みシステムにおいては、個別のゲストオペレーティングシステムをサポートするために仮想マシンを使用することが一般的です。典型的な使用例としては、 LinuxやWindowsなどの優先される複雑なオペレーティングシステムと同時にリアルタイムオペレーティングシステムを実行することが挙げられます。また、開発段階にある新規かつ未検証のソフトウェアをサンドボックス内で実行するためにも使用されます。仮想マシンには、オペレーティングシステム開発において他にも利点があり、デバッグアクセスの改善や再起動の高速化などが挙げられます。[ 5 ]
サーバー統合のために、独自のゲストオペレーティングシステムを実行する複数の仮想マシンがよく利用される。[ 6 ]
プロセス仮想マシン(アプリケーション仮想マシン、またはマネージドランタイム環境(MRE)とも呼ばれる)は、ホストOS内で通常のアプリケーションとして実行され、単一のプロセスをサポートします。プロセスが開始されると作成され、プロセスが終了すると削除されます。その目的は、基盤となるハードウェアやオペレーティングシステムの詳細を抽象化し、どのプラットフォームでも同じようにプログラムを実行できるようにする、プラットフォームに依存しないプログラミング環境を提供することです。[ 7 ]
プロセスVMは、高レベルの抽象化(システムVMの低レベルISA抽象化と比較して)を提供します。これは、高レベルプログラミング言語の抽象化に相当します。プロセスVMはインタプリタを使用して実装され、ジャストインタイムコンパイルを使用することで、コンパイル型プログラミング言語に匹敵するパフォーマンスを実現できます。
この種の仮想マシンは、 Java仮想マシンを使用して実装されているJavaプログラミング言語で広く普及しています。その他の例としては、Parrot仮想マシンや、共通言語ランタイムと呼ばれる仮想マシン上で動作する.NET Frameworkなどがあります。これらはすべて、あらゆるプログラミング言語の抽象化レイヤーとして機能します。
プロセスVMの特殊なケースとして、(潜在的に異種混在の)コンピュータクラスタの通信メカニズムを抽象化するシステムがあります。このようなVMは単一のプロセスではなく、クラスタ内の物理マシンごとに1つのプロセスで構成されます。プログラマが相互接続やOSが提供する通信メカニズムではなくアルゴリズムに集中できるようにすることで、並行アプリケーションのプログラミングを容易にするように設計されています。通信が行われているという事実を隠蔽せず、そのためクラスタを単一のマシンとして表現しようとはしません。
他のプロセス仮想マシンとは異なり、これらのシステムは特定のプログラミング言語を提供するのではなく、既存の言語に組み込まれています。通常、このようなシステムは複数の言語(例えば、C言語とFortran言語)のバインディングを提供します。例としては、並列仮想マシン(PVM)やメッセージパッシングインターフェース(MPI)が挙げられます。
システム仮想マシンとプロセス仮想マシンはどちらも1960年代に誕生し、現在も活発な開発が続けられている分野である。
システム仮想マシンは、互換タイムシェアリングシステム(CTSS)で特に実装されたタイムシェアリングから発展しました。タイムシェアリングでは、複数のユーザーがコンピュータを同時に使用できました。各プログラムはマシンへの完全なアクセス権を持っているように見えましたが、実際に実行されるのは一度に1つのプログラムのみで、システムはタイムスライスでプログラムを切り替え、その都度状態を保存および復元しました。これが仮想マシンへと発展し、特にIBMの研究システムである部分仮想化を使用したM44/44X 、および完全仮想化を使用したCP-40とSIMMON (ハイパーバイザの初期の例)を通じて発展しました。広く利用可能になった最初の仮想マシンアーキテクチャはCP-67 /CMSでした(詳細は「CP/CMSの歴史」を参照)。重要な違いは、M44/44XやCP-40のように、1つのホストシステム上で複数の仮想マシンを使用してタイムシェアリングを行うことと、SIMMONのように、ホストシステム上で1つの仮想マシンを使用してプロトタイプを作成することでした。互換性のために以前のシステムをハードウェアでエミュレートするエミュレータは、1963年のIBM System/360に遡ります[ 8 ] [ 9 ]が、ソフトウェアエミュレーション(当時は「シミュレーション」と呼ばれていました)はそれよりも前に存在していました。
プロセス仮想マシンは、もともとコンパイラによるプログラムの中間表現として使用される中間言語の抽象プラットフォームとして出現しました。初期の例は、構文記述とターゲットコード生成の両方にそれを使用するMETA IIコンパイラ記述システムで、1964年頃に遡ります。1966年の注目すべき例は、 BCPLコンパイラのフロントエンドによって生成されたOコード(オブジェクトコード)を実行する仮想マシンであるOコードマシンです。この抽象化により、既存のOコードを受け取り、それを基盤となる物理マシン用のマシンコードにコンパイルする新しいバックエンドを実装することで、コンパイラを新しいアーキテクチャに簡単に移植することができました。Euler言語も同様の設計を使用しており、中間言語はP(ポータブル)と呼ばれています。[ 10 ]これは、1970年頃にPascalによって普及し、特にPascal-Pシステム(1973年)とPascal-Sコンパイラ(1975年)で普及し、 pコードと呼ばれ、結果として得られるマシンはpコードマシンと呼ばれました。これは影響力があり、この意味での仮想マシンは一般的に p コード マシンと呼ばれることが多い。中間言語であることに加えて、Pascal p コードは、特にUCSD Pascal (1978) で仮想マシンを実装するインタプリタによって直接実行された。これは後のインタプリタ、特にJava 仮想マシン(JVM) に影響を与えた。もう 1 つの初期の例はSNOBOL4 (1967) で、これは仮想マシン用のアセンブリ言語である SNOBOL 実装言語 (SIL) で書かれ、マクロアセンブラを介してネイティブ アセンブラにトランスパイルすることで物理マシンをターゲットにした。[ 11 ]しかし、その後マクロは人気がなくなったため、このアプローチの影響力は小さくなった。プロセス仮想マシンは、 Tiny BASICやアドベンチャーゲームなどの初期のマイクロコンピュータソフトウェアを実装するための一般的なアプローチであり、 Pyramid 2000のような単発の実装から、 Infocomのz-machineのような汎用エンジンまで多岐にわたります。Graham Nelsonは、z-machineは「おそらくこれまで作成された中で最も移植性の高い仮想マシン」であると主張しています。[ 12 ]
Smalltalk -80の実装では大きな進歩がありましたが[ 13 ] 、 特に Deutsch/Schiffmann 実装[ 14 ] は、プロセス仮想マシンを使用する実装アプローチとして、ジャストインタイム (JIT) コンパイルを推進しました[ 15 ] 。 その後、注目すべき Smalltalk VM には、VisualWorks、Squeak 仮想マシン[ 16 ]、Strongtalk [ 17 ] がありました。 仮想マシンの革新を多く生み出した関連言語はSelfプログラミング言語[ 18 ]で、適応型最適化[ 19 ]と世代別ガベージコレクションを先駆的に導入しました。これらの技術は、1999 年にHotSpot Java 仮想マシンで商業的に成功しました[ 20 ]。その他の革新としては、プログラミング言語により近いスタックベースの仮想マシンではなく、基盤となるハードウェアによりよく適合するレジスタベースの仮想マシンがあります。これは、1995 年にLimbo言語用のDis 仮想マシンによって先駆的に導入されました。

完全仮想化では、仮想マシンは、変更されていない「ゲスト」OS(同じ命令セット用に設計されたOS)を独立して実行できるだけのハードウェアをシミュレートします。このアプローチは、 VMファミリーの前身であるIBM CP-40とCP-67によって1966年に初めて導入されました。
メインフレーム以外の分野の例としては、Parallels Workstation、Parallels Desktop for Mac、VirtualBox、Virtual Iron、Oracle VM、Virtual PC、Virtual Server、Hyper-V、VMware Fusion、VMware Workstation、VMware Server(販売終了、旧称GSX Server)、VMware ESXi、QEMU、Adeos、Mac-on-Linux、Win4BSD、Win4Lin Pro、およびEgenera vBladeテクノロジーなどが挙げられます。
ハードウェア支援仮想化では、ハードウェアが仮想マシンモニタの構築を容易にし、ゲストOSを分離して実行できるようにするアーキテクチャサポートを提供します。[ 21 ]ハードウェア支援仮想化は、IBMが公式製品として提供した最初の仮想マシンオペレーティングシステムであるVM/370 で使用するために、1972年にIBM System/370で初めて導入されました。[ 22 ]
2005年と2006年には、IntelとAMDが仮想化をサポートする追加ハードウェアを提供しました。Sun Microsystems(Oracle Corporationに買収)は、2005年にUltraSPARC Tシリーズプロセッサに同様の機能を追加しました。このようなハードウェアに対応した仮想化プラットフォームの例としては、KVM、VMware Workstation、VMware Fusion、Hyper-V、Windows Virtual PC、Xen、Parallels Desktop for Mac、Oracle VM Server for SPARC、VirtualBox 、 Parallels Workstationなどがあります。
2006年には、第一世代の32ビットおよび64ビットx86ハードウェアサポートは、ソフトウェア仮想化に比べてパフォーマンス上の利点をほとんど提供しないことが判明した。[ 23 ]
OSレベル仮想化では、物理サーバーがオペレーティングシステムレベルで仮想化され、1台の物理サーバー上で複数の分離された安全な仮想サーバーを実行できます。「ゲスト」オペレーティングシステム環境は、ホストシステムと同じオペレーティングシステムの実行インスタンスを共有します。そのため、「ゲスト」環境の実装にも同じオペレーティングシステムカーネルが使用され、特定の「ゲスト」環境で実行されているアプリケーションは、それをスタンドアロンシステムとして認識します。先駆的な実装はFreeBSD jailsで、その他の例としては、Docker、Solaris Containers、OpenVZ、Linux-VServer、LXC、AIX Workload Partitions、Parallels Virtuozzo Containers、iCore Virtual Accountsなどがあります。
スナップショットとは、仮想マシンの状態、そして一般的にはそのストレージデバイスの状態を、ある特定の時点において記録したものです。スナップショットを使用すると、スナップショット作成時の仮想マシンの状態を後で復元でき、その後発生した変更を事実上元に戻すことができます。この機能は、例えばリスクの高い操作を実行する前のバックアップ手法として役立ちます。 [ 24 ]
仮想マシンはストレージに仮想ディスクをよく使用します。非常に単純な例では、10ギガバイトのハードディスクドライブは10ギガバイトのフラットファイルでシミュレートされます。仮想マシンが物理ディスク上の場所を要求すると、対応するファイルに対する操作に透過的に変換されます。しかし、このような変換レイヤーが存在すると、さまざまな基準に応じて操作を傍受し、異なるファイルに送信することが可能になります。スナップショットが作成されるたびに新しいファイルが作成され、以前のファイルのオーバーレイとして使用されます。新しいデータは最上位のオーバーレイに書き込まれますが、既存のデータを読み取るにはオーバーレイ階層をスキャンする必要があり、その結果、最新バージョンにアクセスします。したがって、スナップショットのスタック全体は事実上単一のコヒーレントディスクになります。その意味で、スナップショットの作成は増分バックアップ技術と似たような働きをします。
仮想マシンのスナップショットには、ランダムアクセスメモリ(RAM)の内容、 BIOS設定、構成設定など、仮想マシンの他のコンポーネントも含まれる場合があります。ビデオゲーム機エミュレータの「セーブステート」機能は、このようなスナップショットの一例です。
スナップショットを復元するとは、そのスナップショット以降に追加されたすべてのオーバーレイレイヤーを破棄または無視し、すべての新しい変更を新しいオーバーレイに反映させることを指します。
上記のスナップショットは、独自のハイパーバイザーを持つ別のホストマシンに移動できます。VMを一時的に停止し、スナップショットを作成し、移動してから新しいホストで再開する操作は、マイグレーションと呼ばれます。古いスナップショットを定期的に同期させていれば、この操作は非常に高速になり、例えば物理ホストがメンテナンスのために停止している間でも、VMは中断することなくサービスを提供できます。
前述の移行メカニズムと同様に、フェイルオーバーはホストに障害が発生した場合でもVMが動作を継続できるようにします。通常、フェイルオーバーは移行処理が停止した場合に発生します。ただし、この場合、VMは現在の状態ではなく、バックアップサーバーに最後に提供されたデータに基づいて、最後に確認された整合性のある状態から動作を継続します。
ネストされた仮想化とは、ある仮想マシンを別の仮想マシン内で実行できる機能を指し、この一般的な概念は任意の深さまで拡張可能です。言い換えれば、ネストされた仮想化とは、1つ以上のハイパーバイザを別のハイパーバイザ内で実行することを指します。ネストされたゲスト仮想マシンの性質は、ホスト仮想マシンと均一である必要はありません。たとえば、アプリケーション仮想化は、ハードウェア仮想化を使用して作成された仮想マシン内に展開できます。[ 25 ]
広く普及しているオペレーティングシステムにハイパーバイザ機能が組み込まれるにつれて、ネストされた仮想化の必要性が高まっています。仮想化環境では、周囲のハイパーバイザがネストされた仮想化をサポートしている場合にのみ、この機能を使用できます。たとえば、Windows 7 は、組み込みの仮想マシン内でWindows XPアプリケーションを実行できます。さらに、インフラストラクチャ・アズ・ア・サービス(IaaS) のアプローチに従って、既存の仮想化環境をクラウドに移行する場合、移行先の IaaS プラットフォームがネストされた仮想化をサポートしていないと、はるかに複雑になります。[ 26 ] [ 27 ]
特定のコンピュータアーキテクチャ上でネストされた仮想化を実装する方法は、サポートされているハードウェア支援仮想化機能に依存します。特定のアーキテクチャがネストされた仮想化に必要なハードウェアサポートを提供しない場合、それを可能にするためにさまざまなソフトウェア技術が使用されます。[ 26 ] 時間の経過とともに、必要なハードウェアサポートを獲得するアーキテクチャが増えています。たとえば、Haswellマイクロアーキテクチャ(2013年に発表)以降、Intelはネストされた仮想化を高速化する技術としてVMCSシャドウイングを含めるようになりました。 [ 28 ]

仮想マシンは、セキュリティ上の理由から、アプリケーション同士を分離するためによく使用されます。
このアーキテクチャ設計( Qubes OS、Whonix、KickSecure 、Dangerzoneで使用)は、マルウェアが侵害されたシステム(感染したドキュメントを開いたメールクライアントなど)から別のシステム(パスワードマネージャーなど)に拡散するのを防ぐことができます。[ 29 ] [ 30 ]
この機能を利用して Mac 上で Windows を実行する別の仮想マシンをセットアップし、両方のプラットフォームで利用可能なすべてのアプリケーションにアクセスできるようにする人もいます。
驚くべきことに、第一世代のハードウェアサポートは、既存のソフトウェア技術に比べてパフォーマンス上の利点をほとんど提供しないことがわかりました。この状況は、VMM/ゲスト移行コストが高いことと、これらの移行の頻度やコストを管理するソフトウェアの柔軟性をほとんど残さない厳格なプログラミングモデルに起因すると考えられます。