次の方法で共有


マネージ実行プロセス

マネージド実行プロセスには、このトピックの後半で詳しく説明する次の手順が含まれています。

  1. コンパイラの選択。 共通言語ランタイムによって提供される利点を取得するには、ランタイムを対象とする 1 つ以上の言語コンパイラを使用する必要があります。
  2. コードを中間言語にコンパイルする。 コンパイルすると、ソース コードが共通の中間言語 (CIL) に変換され、必要なメタデータが生成されます。
  3. ネイティブ コードへの CIL のコンパイル。 実行時に、Just-In-Time (JIT) コンパイラは CIL をネイティブ コードに変換します。 このコンパイル中、コードは CIL とメタデータを調べて、コードが型セーフであると判断できるかどうかを確認する検証プロセスに合格する必要があります。
  4. コードの実行。 共通言語ランタイムは、実行中に実行できるインフラストラクチャと、実行中に使用できるサービスを提供します。

コンパイラを選択する

共通言語ランタイム (CLR) によって提供される利点を得るために、Visual Basic、C#、Visual C++、F# などのランタイムを対象とする 1 つ以上の言語コンパイラ、または Eiffel、Perl、COBOL コンパイラなどの多くのサードパーティ コンパイラのいずれかを使用する必要があります。

これは多言語実行環境であるため、ランタイムはさまざまなデータ型と言語機能をサポートします。 使用する言語コンパイラによって、使用できるランタイム機能が決まります。これらの機能を使用してコードを設計します。 コンパイラはランタイムではなく、コードで使用する必要がある構文を確立します。 コンポーネントが他の言語で記述されたコンポーネントで完全に使用できる必要がある場合、コンポーネントのエクスポートされた型は、共通言語仕様 (CLS) に含まれる言語機能のみを公開する必要があります。 CLSCompliantAttribute属性を使用して、コードが CLS に準拠していることを確認できます。 詳細については、「 言語に依存しないコンポーネントと言語に依存しないコンポーネント」を参照してください。

CIL にコンパイルする

マネージド コードにコンパイルすると、コンパイラはソース コードを共通の中間言語 (CIL) に変換します。これは、CPU に依存しない命令セットであり、ネイティブ コードに効率的に変換できます。 CIL には、オブジェクトのメソッドの読み込み、格納、初期化、呼び出しに関する命令のほか、算術演算と論理操作、制御フロー、ダイレクト メモリ アクセス、例外処理、その他の操作の命令が含まれています。 コードを実行する前に、通常は Just-In-Time (JIT) コンパイラによって CIL を CPU 固有のコードに変換する必要があります。 共通言語ランタイムは、サポートするコンピューター アーキテクチャごとに 1 つ以上の JIT コンパイラを提供するため、同じ CIL セットを JIT コンパイルし、サポートされている任意のアーキテクチャで実行できます。

コンパイラが CIL を生成すると、メタデータも生成されます。 メタデータは、各型の定義、各型のメンバーのシグネチャ、コードが参照するメンバー、実行時にランタイムが使用するその他のデータなど、コード内の型を記述します。 CIL とメタデータは、実行可能ファイルのコンテンツに対して過去に使用される公開済みの Microsoft PE と共通オブジェクト ファイル形式 (COFF) に基づいて拡張されたポータブル実行可能ファイル (PE) ファイルに含まれています。 CIL またはネイティブ コードとメタデータに対応するこのファイル形式により、オペレーティング システムは共通言語ランタイム イメージを認識できます。 ファイルに CIL と共にメタデータが存在すると、コード自体を記述できます。つまり、タイプ ライブラリやインターフェイス定義言語 (IDL) は必要ありません。 ランタイムは、実行時に必要に応じてファイルを検索し、ファイルからメタデータを抽出します。

CIL をネイティブ コードにコンパイルする

共通中間言語 (CIL) を実行する前に、共通言語ランタイムに対してターゲット コンピューター アーキテクチャのネイティブ コードに対してコンパイルする必要があります。 .NET には、この変換を実行する 2 つの方法があります。

JIT コンパイラによるコンパイル

JIT コンパイルでは、アセンブリの内容が読み込まれて実行されるときに、アプリケーションの実行時に CIL を必要に応じてネイティブ コードに変換します。 共通言語ランタイムは、サポートされている CPU アーキテクチャごとに JIT コンパイラを提供するため、開発者は、コンピューター アーキテクチャが異なるさまざまなコンピューターで JIT コンパイルおよび実行できる一連の CIL アセンブリを構築できます。 ただし、マネージド コードがプラットフォーム固有のネイティブ API またはプラットフォーム固有のクラス ライブラリを呼び出す場合、そのオペレーティング システムでのみ実行されます。

JIT コンパイルでは、実行中に一部のコードが呼び出されない可能性が考慮されます。 時間とメモリを使用して PE ファイル内のすべての CIL をネイティブ コードに変換する代わりに、実行時に必要に応じて CIL を変換し、結果のネイティブ コードをメモリに格納して、そのプロセスのコンテキストで後続の呼び出しにアクセスできるようにします。 ローダーは、型が読み込まれて初期化されるときに、型の各メソッドにスタブを作成してアタッチします。 メソッドが初めて呼び出されると、スタブは JIT コンパイラに制御を渡します。このコンパイラは、そのメソッドの CIL をネイティブ コードに変換し、生成されたネイティブ コードを直接指すスタブを変更します。 そのため、JIT コンパイル メソッドの後続の呼び出しは、ネイティブ コードに直接移動します。

NGen.exe を使用したインストール時のコード生成

JIT コンパイラは、そのアセンブリで定義されている個々のメソッドが呼び出されると、アセンブリの CIL をネイティブ コードに変換するため、実行時のパフォーマンスに悪影響を及ぼします。 ほとんどの場合、パフォーマンスの低下は許容されます。 さらに重要なのは、JIT コンパイラによって生成されたコードが、コンパイルをトリガーしたプロセスにバインドされていることです。 複数のプロセス間で共有することはできません。 生成されたコードを、アプリケーションの複数の呼び出し間で、またはアセンブリのセットを共有する複数のプロセス間で共有できるようにするために、共通言語ランタイムは、事前コンパイル モードをサポートします。 この事前コンパイル モードでは 、Ngen.exe (ネイティブ イメージ ジェネレーター) を使用して、JIT コンパイラと同様に CIL アセンブリをネイティブ コードに変換します。 ただし、Ngen.exe の操作は、次の 3 つの方法で JIT コンパイラの操作とは異なります。

  • アプリケーションの実行中ではなく、アプリケーションを実行する前に CIL からネイティブ コードへの変換を実行します。
  • 一度に 1 つのメソッドではなく、アセンブリ全体を一度にコンパイルします。
  • 生成されたコードは、ネイティブ イメージ キャッシュ内のディスク上のファイルとして保持されます。

コードの検証

ネイティブ コードへのコンパイルの一環として、CIL コードは、コードが検証をバイパスできるセキュリティ ポリシーを管理者が確立していない限り、検証プロセスに合格する必要があります。 検証では CIL とメタデータを調べて、コードがタイプ セーフかどうかを調べます。つまり、アクセスが許可されているメモリの場所にのみアクセスします。 タイプ セーフは、オブジェクトを互いに分離し、不注意や悪意のある破損からオブジェクトを保護するのに役立ちます。 また、コードに対するセキュリティ制限を確実に適用できることを保証します。

ランタイムは、検証可能に型セーフなコードに対して次のステートメントが当てはまるという事実に依存します。

  • 型への参照は、参照される型と厳密に互換性があります。
  • オブジェクトに対して適切に定義された操作のみが呼び出されます。
  • 各々のアイデンティティは、自己主張どおりのものです。

検証プロセス中に、コードがメモリの場所にアクセスし、適切に定義された型を介してのみメソッドを呼び出すことができることを確認するために、CIL コードが調べられます。 たとえば、メモリの場所をオーバーランできるようにする方法で、オブジェクトのフィールドへのアクセスをコードで許可することはできません。 さらに、CIL が正しく生成されていないと、型の安全性規則に違反する可能性があるため、検証によってコードが検査され、CIL が正しく生成されたかどうかが判断されます。 検証プロセスは、型セーフコードの明確に定義されたセットを渡し、タイプ セーフなコードのみを渡します。 ただし、一部の型セーフ コードは検証プロセスの一部の制限のために検証に合格しない可能性があり、一部の言語では仕様上、検証可能な型セーフ コードが生成されません。 セキュリティ ポリシーでタイプ セーフなコードが必要であっても、コードが検証に合格しない場合は、コードの実行時に例外がスローされます。

コードの実行

共通言語ランタイムは、マネージド実行を実行できるインフラストラクチャと、実行中に使用できるサービスを提供します。 メソッドを実行する前に、プロセッサ固有のコードにコンパイルする必要があります。 CIL が生成された各メソッドは、最初に呼び出されたときに JIT コンパイルされ、次に実行されます。 次にメソッドを実行すると、既存の JIT コンパイル ネイティブ コードが実行されます。 JIT コンパイルしてからコードを実行するプロセスは、実行が完了するまで繰り返されます。

実行中、マネージド コードは、ガベージ コレクション、セキュリティ、アンマネージ コードとの相互運用性、言語間デバッグのサポート、拡張されたデプロイとバージョン管理のサポートなどのサービスを受け取ります。

Microsoft Windows Vista では、オペレーティング システム ローダーは、COFF ヘッダーで少し調べることで、マネージド モジュールをチェックします。 設定されているビットは、マネージド モジュールを表します。 ローダーがマネージド モジュールを検出すると、mscoree.dllが読み込まれ、_CorValidateImage_CorImageUnloading がマネージド モジュール イメージがロードおよびアンロードされた際にローダーに通知します。 _CorValidateImage は、次のアクションを実行します。

  1. コードが有効なマネージド コードであることを確認します。
  2. イメージ内のエントリ ポイントをランタイムのエントリ ポイントに変更します。

64 ビット Windows では、 _CorValidateImage は PE32 から PE32+ 形式に変換することで、メモリ内のイメージを変更します。

こちらも参照ください