これは、共通言語ランタイムの内部を調べるより詳細な説明です。
まず、値型と参照型を区別してみましょう。
- 値型はスタックに保持され、そのコピーが呼び出されたメソッドに渡されます
- 参照値は管理対象ヒープに保持され、スタックはその場所へのポインター(参照)のみを保持します。オブジェクトではなく、場所が呼び出されたメソッドに渡されます
スタックが何であるかわからない場合(気分を害しないでください)、それはメソッド内のローカル変数とreturn
命令に使用される呼び出し元関数のアドレスを保持するメモリ領域です(簡単に説明して一般的な答えを提供します)。メソッドを呼び出すと、スタック上の十分な領域が静的に割り当てられるため、スタックの割り当ては常に静的割り当てと呼ばれます。
代わりに、ヒープは、実行中のプロセスのプロパティであるスタックから分離されたメモリ領域であり、オペレーティングシステムに最初に割り当てを要求する必要があるため、動的割り当てと呼ばれます(ifステートメントで実行しない場合)。たとえば、メモリがプロセスに割り当てられていない場合、代わりにスタックが常に割り当てられます)。
ヒープとスタックの最後の例を示すために:C ++などの言語では、宣言するとスタックint[100] a;
に100 * 8バイトが静的に割り当てられ(64ビットシステムを想定)、int* a = new int[100];
宣言すると8バイト(64ビットシステムの場合)の領域が宣言されます。スタックANDは、使用可能な場合、ヒープ上にさらに800バイトを要求します。
それでは、C#について話しましょう。
ボクシング
intは値型であり、スタックに割り当てられるため、オブジェクトまたは他の参照型にキャストする場合(実際には、intが継承できる他の参照型はありませんが、原則として)、値は必然的になる必要があります。参照型。そのため、ヒープ上の新しい領域が割り当てられ、オブジェクトはその中にボックス化され、スタックはその領域へのポインタを保持します。
開箱
正反対です。オブジェクトなどの参照型があり、それをintなどの値型にキャストする場合は、新しい値をスタックに保持する必要があるため、CLRはヒープに移動し、ボックスを解除します。値を設定し、スタックにコピーします。
言い換えると
int[]
とint*
例を覚えていますか?簡単に言うと、int
C#を使用している場合、ランタイムはスタックの場所が値を保持することを期待しますがobject
、代わりに、を使用している場合、実際の値はスタックが指すヒープの場所にあることを期待します。