質問

JITコンパイラとCLRの違いは何ですか?コードをilにコンパイルし、CLRがそのコードを実行すると、JITは何をしますか? CLRへのジェネリックの追加により、JITコンパイルはどのように変わりましたか?

役に立ちましたか?

解決

JITはCLRの1つの側面です。

具体的には、元の言語のコンパイラ(Microsoft c#の場合はcsc.exeなど)によって生成されたCIL / MSIL(以降ILと呼びます)を現在のプロセッサ(および公開するアーキテクチャ)に固有のマシンコードに変更する部分です現在のプロセス(32/64ビットなど)。問題のアセンブリがngenされた場合、JITプロセスは完全に不要であり、CLRはこのコードをそれなしで正常に実行します。

中間表現からまだ変換されていないメソッドを使用する前に、変換するのはJITの責任です。
JITが正確にいつ起動するかは実装固有であり、変更される可能性があります。ただし、CLRの設計では、関連するコードが実行される前にJITが発生することを義務付けていますが、対照的にJVMはしばらくの間コードを自由に解釈できますが、別のスレッドがマシンコード表現を作成します。
「通常の」CLRは pre-JITスタブアプローチここで、byメソッドは使用時にのみJITコンパイルされます。これには、最初のネイティブメソッドスタブをインダイレクションにして、メソッドをコンパイルするようにJITに指示し、最初のスタブをスキップするように元の呼び出しを変更することが含まれます。代わりに、現在のコンパクトエディションは、タイプがロードされると、そのタイプのすべてのメソッドをコンパイルします。

ジェネリックの追加に対処する。

これは、内部実装の詳細とは対照的に、セマンティクスの点でIL仕様およびJITに対する最後の主要な変更でした。

新しいIL命令がいくつか追加され、タイプとメンバーをインスツルメントするためのメタデータオプションが追加されました。 ILレベルでも制約が追加されました。

JITがジェネリック引数を持つメソッドをコンパイルするとき(包含クラスを介して明示的または暗黙的に)、使用するタイプごとに異なるコードパス(マシンコード命令)を設定できます。実際には、これらの変数は同じセマンティクスを示し、同じスペース(IntPtr.Size)を占有するため、JITはすべての参照タイプに共有実装を使用します。

各値タイプは、そのために生成された特定のコードを取得します。スタック/ヒープ上の変数のサイズの減少/増加に対処することが、この主な理由です。また、メソッドを呼び出す前に制約付きオペコードを発行することにより、非参照型での多くの呼び出しでは、メソッドを呼び出すために値をボックス化する必要がありません(この最適化は一般的でない場合にも使用されます)。これにより、デフォルトの<T>動作を正しく処理し、Null以外の値タイプが使用されている場合に、操作なし(常にfalse)としてnullとの比較を削除できます。

実行時にリフレクションを介してジェネリック型のインスタンスを作成しようとすると、型パラメーターはランタイムによって検証され、制約を渡すことが保証されます。これは、型システム内で使用しない限り、JITに直接影響しません(可能性は低いですが)。

他のヒント

コードをILにコンパイルすると、実行時に実行され、マシンコードにコンパイルされます。これをJITと呼びます。

編集、回答をさらに具体化するために(さらに簡略化しすぎています):

Visual StudioでC#コードをコンパイルすると、CLRが理解できるILに変換されます。ILは、CLR上で実行されるすべての言語で同じです(これにより、.NETランタイムは複数の言語を使用できます。簡単に相互運用できます)。

実行中に、ILはマシンコード(現在使用しているアーキテクチャに固有)に解釈され、実行されます。このプロセスは、Just In Timeコンパイルまたは略してJITと呼ばれます。必要なILのみがマシンコードに変換され(一度だけ、<!> quot; cached <!> quot;マシンコードにコンパイルされると)、実行される直前に適時に JITという名前。

これはC#の場合の外観です

  

C#コード> C#コンパイラ<=> IL <=> .NETランタイム<=> JITコンパイラ<=>マシンコード<=>実行

そして、これはVBのように見えるものです

  

VBコード<=> VBコンパイラー<=> IL <=> .NETランタイム<=> JITコンパイラー<=>マシンコード<=>実行

おわかりのように、最初の2つのステップのみが各言語に固有であり、ILに変換された後はすべて同じです。これは、前に述べたように、で複数の異なる言語を実行できる理由です。 NET

Jon Skeetが言うように、JITはCLRの一部です。基本的に、これは内部で行われていることです:

  1. ソースコードは、共通中間言語(CIL)として知られるバイトコードにコンパイルされます。
  2. すべてのクラスおよびすべてのメソッドからのメタデータ(およびその他すべて:O)は、結果の実行可能ファイル(dllでもexeでも)のPEヘッダーに含まれます。
  3. 実行可能ファイルを作成する場合、PEヘッダーには、実行可能ファイルを実行するときにCLR(共通言語ランタイム)の読み込みを担当する従来のブートストラップも含まれます。

今、実行すると:

  1. ブートストラッパーはCLRを初期化し(主にmscorlibアセンブリをロードすることにより)、アセンブリの実行を指示します。
  2. CLRがメインエントリを実行します。
  3. 現在、クラスにはメソッド関数のアドレスを保持するベクターテーブルがあるため、MyMethodを呼び出すと、このテーブルが検索され、アドレスに対応する呼び出しが行われます。開始時には、すべてのテーブルのすべてのエントリにJITコンパイラのアドレスがあります。
  4. そのようなメソッドの1つが呼び出されると、実際のメソッドの代わりにJITが呼び出され、制御を取得します。次に、JITはCILコードを適切なアーキテクチャの実際のアセンブリコードにコンパイルします。
  5. コードがコンパイルされると、JITはメソッドベクタテーブルに入り、コンパイルされたコードの1つでアドレスを置き換えます。これにより、以降のすべての呼び出しでJITが呼び出されなくなります。
  6. 最後に、JITはコンパイルされたコードの実行を処理します。
  7. まだコンパイルされていない別のメソッドを呼び出す場合は、4 ...に戻るなど...

JITは基本的にCLRの一部です。ガベージコレクターは別です。相互運用の責任などをどこに置くかは別の問題であり、私はコメントするのが非常に不十分です:

スレッドがかなり古いことは知っていますが、JITを理解できるようになった写真に入れると思いました。これは、優れた本ジェフリーリッチャーによるC#経由のCLR からのものです。写真では、彼が話しているメタデータは、アセンブリヘッダーで発行されたメタデータで、アセンブリの型に関するすべての情報が格納されています。

CLRを介したCLRからのJIT画像

1).netプログラムのコンパイル中、.netプログラムコードは中間言語(IL)コードに変換されます

2)プログラムを実行すると、メソッドが呼び出されたときに中間言語コードがオペレーティングシステムのネイティブコードに変換されます。これはJIT(Just in Time)コンパイルと呼ばれます。

  1. 共通言語ランタイム(CLR)はインタープリターであり、ジャストインタイム(JIT)は.Net Frameworkのコンパイラーです。

2.JITは.NETの内部コンパイラであり、CLRからMicroSoft Intermediate Code Language(MSICL)コードを取得してマシン固有の命令に実行しますが、CLRはエンジンとして動作し、その主なタスクはJITにMSICLコードを提供することですそのコードはマシン仕様に従って完全にコンパイルされます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top