配列はヒープに割り当てられ、intはボックス化されません。
参照型はヒープに割り当てられ、値型はスタックに割り当てられると人々が言っているため、混乱の原因が考えられます。これは完全に正確な表現ではありません。
すべてのローカル変数とパラメーターはスタックに割り当てられます。これには、値タイプと参照タイプの両方が含まれます。2つの違いは、変数に格納されるものだけです。当然のことながら、値型の場合、型の値は直接変数に格納され、参照型の場合、型の値はヒープに格納され、この値への参照は変数に格納されます。
フィールドについても同様です。集計タイプ(a class
またはastruct
)の、そのインスタンスフィールドごとにストレージが含まれている必要があります。参照タイプのフィールドの場合、このストレージは値への参照のみを保持します。値自体は後でヒープに割り当てられます。値タイプのフィールドの場合、このストレージには実際の値が保持されます。
したがって、次のタイプが与えられます:
class RefType{
public int I;
public string S;
public long L;
}
struct ValType{
public int I;
public string S;
public long L;
}
これらの各タイプの値には、16バイトのメモリが必要です(32ビットのワードサイズを想定)。フィールドI
それぞれの場合には、その値を格納するために4つのバイトをとり、フィールドは、S
その参照を格納するために4つのバイトを取り、フィールドはL
その値を格納する8つのバイトを取ります。両方の値のためのメモリだから、RefType
とValType
次のようになります。
0┌───────────────────┐
│I│
4├───────────────────┤
│S│
8├───────────────────┤
│L│
││
16└───────────────────┘
今、あなたはタイプの関数内の3つのローカル変数を、持っていた場合RefType
、ValType
およびint[]
、このように:
RefType refType;
ValType valType;
int[] intArray;
スタックは次のようになります。
0┌───────────────────┐
│refType│
4├───────────────────┤
│valType│
││
││
││
20├───────────────────┤
│intArray│
24└───────────────────┘
次のように、これらのローカル変数に値を割り当てた場合:
refType = new RefType();
refType.I = 100;
refType.S = "refType.S";
refType.L = 0x0123456789ABCDEF;
valType = new ValType();
valType.I = 200;
valType.S = "valType.S";
valType.L = 0x0011223344556677;
intArray = new int[4];
intArray[0] = 300;
intArray[1] = 301;
intArray[2] = 302;
intArray[3] = 303;
次に、スタックは次のようになります。
0┌───────────────────┐
│0x4A963B68│-`refType`のヒープアドレス
4├───────────────────┤
│200│-`valType.I`の値
│0x4A984C10│-「valType.S」のヒープアドレス
│0x44556677│-`valType.L`の下位32ビット
│0x00112233│-`valType.L`の上位32ビット
20├───────────────────┤
│0x4AA4C288│-「intArray」のヒープアドレス
24└───────────────────┘
アドレス0x4A963B68
(の値refType
)のメモリは次のようになります。
0┌───────────────────┐
│100│-`refType.I`の値
4├───────────────────┤
│0x4A984D88│-「refType.S」のヒープアドレス
8├───────────────────┤
│0x89ABCDEF│-「refType.L」の下位32ビット
│0x01234567│-`refType.L`の上位32ビット
16└───────────────────┘
アドレス0x4AA4C288
(の値intArray
)のメモリは次のようになります。
0┌───────────────────┐
│4│-配列の長さ
4├───────────────────┤
│300│-`intArray [0]`
8├───────────────────┤
│301│-`intArray [1]`
12├───────────────────┤
│302│-`intArray [2]`
16├───────────────────┤
│303│-`intArray [3]`
20└───────────────────┘
これで、intArray
別の関数に渡した場合、スタックにプッシュされる値0x4AA4C288
は、配列のコピーではなく配列のアドレスになります。