7

ECMA-335、I.12.3.2.4 には次のように記載されています。

各メソッド状態の一部は、ローカル メモリ プールです。locallocメモリは、命令を使用してローカル メモリ プールから明示的に割り当てることができます。ローカル メモリ プール内のすべてのメモリは、メソッドの終了時に回収されます。これが、ローカル メモリ プール メモリを回収する唯一の方法です (このメソッドの呼び出し中に割り当てられたローカル メモリを解放するための命令は提供されていません)。ローカル メモリ プールは、コンパイル時に型やサイズが不明で、プログラマがマネージ ヒープに割り当てたくないオブジェクトを割り当てるために使用されます。メソッドの有効期間中にローカル メモリ プールを縮小することはできないため、言語実装ではローカル メモリ プールを汎用メモリ割り当てに使用することはできません。

CLR はこのメモリ プールをどこに割り当てますか? マネージ ヒープ、スレッド スタックなどでしょうか。

4

1 に答える 1

9

これは、CLI 仕様が明らかにしたくない強力な実装の詳細であるため、すべて意図的に曖昧にしています。ただし、 Opcodes.Locallocに関する MSDN の記事の隙間から覗いています。

リクエストを処理するのに十分なメモリがない場合、StackOverflowException がスローされます。

SOE を取得する唯一の方法は、スタックから割り当てる必要があることです。

C# 言語は、どこに割り当てられるかについて恥ずかしがり屋ではなく、stackallocキーワードを使用します。サンプルプログラム:

class Program {
    static unsafe void Main(string[] args) {
        int* p = stackalloc int[42];
    }
}

この IL を生成します。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       9 (0x9)
  .maxstack  8
  IL_0000:  ldc.i4.s   42
  IL_0002:  conv.u
  IL_0003:  ldc.i4.4
  IL_0004:  mul.ovf.un
  IL_0005:  localloc                   // <=== Here
  IL_0007:  pop
  IL_0008:  ret
} // end of method Program::Main

実行時にこのマシン コードを生成します。

02E42620  push        ebp  
02E42621  mov         ebp,esp  
02E42623  sub         esp,8  
02E42626  mov         dword ptr [ebp-4],esp  
02E42629  mov         dword ptr [ebp-8],6A029823h  
02E42630  mov         eax,esp  
02E42632  test        dword ptr [esp],esp  
02E42635  sub         eax,0A8h                       // <=== Here
02E4263A  mov         esp,eax  
02E4263C  mov         dword ptr [ebp-4],esp  
02E4263F  cmp         dword ptr [ebp-8],6A029823h  
02E42646  je          02E4264D  
02E42648  call        730CA5C0  
02E4264D  lea         esp,[ebp]  
02E42650  pop         ebp  
02E42651  ret  

このsub eax,0A8h命令は、ESP レジスタ (スタック ポインター) から 0xa8 = 168 = 42x4 バイトを減算しmov esp,eax、スタック ポインターを調整します。はい、これは間違いなくスタックからのものです。

于 2013-10-27T15:37:11.497 に答える