1. ホーム
  2. c#

[解決済み] C#のJITコンパイルと.NET

2023-03-01 13:55:40

質問

JIT コンパイラがどのように動作するかの詳細について、少し混乱しています。C# が IL にまでコンパイルされることは知っています。最初に実行されるとき、それは JIT されます。これは、ネイティブコードに変換されることを意味するのでしょうか。.NETランタイム(仮想マシンとして)は、JITされたコードと対話するのですか?私はこれが単純であることを知っているが、私は本当に自分自身を混乱させている。私の印象では、アセンブリは .NET ランタイムによって解釈されませんが、相互作用の詳細については理解していません。

どのように解決するのですか?

IL コードの JIT 化には、IL をネイティブのマシン命令に変換することが含まれます。

はい、.NET ランタイムは、ランタイムがネイティブ マシン コードが占有するメモリ ブロックを所有し、ランタイムがネイティブ マシン コードを呼び出すなどの意味で、JIT したネイティブ マシン コードと相互作用しています。

.NET ランタイムがアセンブリ内の IL コードを解釈しないことは正しいです。

実行が、まだネイティブのマシン コードに JIT コンパイルされていない関数またはコード ブロック (if ブロックの else 節など) に達すると、JIT が呼び出されて IL のそのブロックをネイティブのマシン コードにコンパイルします。 それが完了すると、プログラムの実行は、新しく生成されたマシンコードに入り、プログラムロジックを実行する。 そのネイティブなマシンコードの実行中に、まだマシンコードにコンパイルされていない関数への関数呼び出しに到達した場合、JIT'r が呼び出されて その 関数をコンパイルします。 といった具合です。

JIT'r は、関数本体のすべてのロジックを一度にマシンコードにコンパイルするとは限りません。 関数に if 文がある場合、if 節または else 節のステートメントブロックは、実行が実際にそのブロックを通過するまで JIT コンパイルされないことがあります。 実行されていないコード パスは、実行されるまで IL 形式のままです。

コンパイルされたネイティブ マシン コードは、コードのセクションが次に実行されたときに再び使用できるように、メモリ内に保持されます。 関数を 2 回目に呼び出したときは、2 回目に JIT ステップが必要ないため、最初に呼び出したときよりも高速に実行されます。

デスクトップ .NET では、ネイティブ マシン コードはアプリ ドメインの有効期間中、メモリ内に保持されます。 .NET CF では、アプリケーションがメモリ不足になると、ネイティブ マシン コードは破棄されることがあります。 次に実行がそのコードを通過するときに、元の IL コードから再び JIT コンパイルされます。