JITコンパイラの動作の詳細について少し混乱しました。私はC#がILにコンパイルされることを知っています。初めて実行されるときはJITされます。これには、ネイティブコードに変換されることが含まれますか?.NETランタイム(仮想マシンとして?)はJITされたコードと相互作用しますか?私はこれが素朴であることを知っていますが、私は本当に自分自身を混乱させました。私の印象では、アセンブリは.NETランタイムによって解釈されませんが、相互作用の詳細はわかりません。
回答:
はい、ILコードのJITには、ILをネイティブマシン命令に変換することが含まれます。
はい。.NETランタイムは、ランタイムがネイティブマシンコードによって占有されているメモリブロックを所有しているという意味で、JITされたネイティブマシンコードと相互作用します。ランタイムはネイティブマシンコードを呼び出します。
.NETランタイムがアセンブリ内のILコードを解釈しないのは正しいことです。
実行がまだネイティブマシンコードにJITコンパイルされていない関数またはコードブロック(ifブロックのelse句など)に到達すると、JIT'rが呼び出されてILのそのブロックがネイティブマシンコードにコンパイルされます。 。それが完了すると、プログラムの実行は、新しく発行されたマシンコードを入力して、そのプログラムロジックを実行します。そのネイティブマシンコードの実行中に、マシンコードにまだコンパイルされていない関数への関数呼び出しに到達すると、JIT'rが呼び出され、その関数が「ジャストインタイム」でコンパイルされます。等々。
JIT'rは、必ずしも関数本体のすべてのロジックを一度にマシンコードにコンパイルするわけではありません。関数にifステートメントがある場合、ifまたはelse節のステートメントブロックは、実行が実際にそのブロックを通過するまでJITコンパイルされない場合があります。実行されなかったコードパスは、実行されるまでIL形式のままになります。
コンパイルされたネイティブマシンコードはメモリに保持されるため、次にコードのそのセクションを実行するときに再び使用できます。2回目に関数を呼び出すと、2回目にJITステップが不要になるため、最初に呼び出すときよりも高速に実行されます。
デスクトップ.NETでは、ネイティブマシンコードはappdomainの存続期間中メモリに保持されます。.NET CFでは、アプリケーションのメモリが不足している場合、ネイティブマシンコードが破棄される可能性があります。次回実行がそのコードを通過するときに、元のILコードから再度JITコンパイルされます。
コードは、アセンブリ形式に似たMicrosoft中間言語に「コンパイル」されます。
実行可能ファイルをダブルクリックすると、Windowsが読み込まmscoree.dll
れ、CLR環境がセットアップされ、プログラムのコードが開始されます。JITコンパイラは、プログラム内のMSILコードの読み取りを開始し、CPUが実行できるx86命令にコードを動的にコンパイルします。
以下の例を使用して、ILコードをネイティブCPU命令にコンパイルする方法について説明します。
public class Example
{
static void Main()
{
Console.WriteLine("Hey IL!!!");
}
}
主にCLRは、タイプに関するすべての詳細と、そのタイプから呼び出されているメソッドがメタデータに起因することを認識しています。
CLRがネイティブCPU命令にILを実行し始めると、CLRはMainのコードによって参照されるすべてのタイプに内部データ構造を割り当てます。
この場合、タイプコンソールは1つしかないため、CLRはその内部構造を介して1つの内部データ構造を割り当て、参照されるタイプへのアクセスを管理します。
そのデータ構造内に、CLRにはそのタイプで定義されたすべてのメソッドに関するエントリがあります。各エントリは、メソッドの実装を見つけることができるアドレスを保持します。
この構造を初期化すると、CLRは、CLR自体に含まれる文書化されていないFUNCTIONの各エントリを設定します。ご想像のとおり、このFUNCTION はJITコンパイラと呼ばれます。
全体として、JITコンパイラはILをネイティブCPU命令にコンパイルするCLR関数と見なすことができます。この例でこのプロセスがどのようになるかを詳しく説明します。
1. MainがWriteLineを最初に呼び出すと、JITCompiler関数が呼び出されます。
2.JITコンパイラ関数は、呼び出されているメソッドと、このメソッドを定義するタイプを認識しています。
3.次に、Jitコンパイラは、そのタイプが定義されているアセンブリを検索し、そのタイプで定義されているメソッドのILコード(この場合はWriteLineメソッドのILコード)を取得します。
4.JITコンパイラはDYNAMICメモリブロックを割り当てます。その後、JITはILコードを検証してネイティブCPUコードにコンパイルし、そのCPUコードをそのメモリブロックに保存します。
5.次に、JITコンパイラは内部データ構造エントリに戻り、アドレス(主にWriteLineのILコード実装を参照)を、WriteLineのネイティブCPU命令を含む動的に作成された新しいメモリブロックのアドレスに置き換えます。
6.最後に、JITコンパイラ関数はメモリブロック内のコードにジャンプします。このコードは、WriteLineメソッドの実装です。
7.WriteLineの実装後、コードはMainsのコードに戻り、通常どおり実行を継続します。
.NET Frameworkは、CLR環境を使用して、ILとも呼ばれるMSIL(Microsoft中間言語)を生成します。コンパイラはソースコードを読み取り、プロジェクトをビルド/コンパイルすると、MSILが生成されます。これで、最終的にプロジェクトを実行すると、.NET JIT(ジャストインタイムコンパイラ)が動作します。JITはMSILコードを読み取り、CPUで簡単に実行できるネイティブコード(x86命令)を生成します。JITはすべてのMSIL命令を読み取り、それらを1行ずつ実行します。
舞台裏で何が起こっているのかを知りたい場合は、すでに回答済みです。フォローしてください-ここ