配列はヒープに割り当てられ、intはボックス化されていません。
参照型はヒープに割り当てられ、値型はスタックに割り当てられると人々が言っているため、混乱の原因となる可能性があります。これは完全に正確な表現ではありません。
すべてのローカル変数とパラメーターはスタックに割り当てられます。これには、値型と参照型の両方が含まれます。2つの違いは、変数に格納されているものだけです。当然のことながら、値型の場合、型の値は変数に直接格納され、参照型の場合、型の値はヒープに格納され、この値への参照が変数に格納されます。
同じことがフィールドにも当てはまります。class
集約タイプ(aまたはa )のインスタンスにメモリを割り当てる場合、struct
各インスタンスフィールドのストレージを含める必要があります。参照型フィールドの場合、このストレージは値への参照のみを保持し、それ自体は後でヒープに割り当てられます。値型フィールドの場合、このストレージは実際の値を保持します。
したがって、次のタイプが与えられます。
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バイトかかり、フィールドは参照を格納するのに4バイトかかり、フィールドはS
値L
を格納するのに8バイトかかります。したがって、両方の値のメモリは次のようにRefType
なりValType
ます。
0┌───────────────────┐
│私│
4├───────────────────┤
│S│
8├───────────────────┤
│L│
││
16└───────────────────┘
ここで、関数に、、、、およびのタイプRefType
の3つのローカル変数がある場合、次のようになります。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│-上位32ビットの`valType.L`
20├───────────────────┤
│0x4AA4C288│-`intArray`のヒープアドレス
24└───────────────────┘
0x4A963B68
アドレス(の値)のメモリは次のrefType
ようになります。
0┌───────────────────┐
│100│-`refType.I`の値
4├───────────────────┤
│0x4A984D88│-`refType.S`のヒープアドレス
8├───────────────────┤
│0x89ABCDEF│-`refType.L`の下位32ビット
│0x01234567│-上位32ビットの`refType.L`
16└───────────────────┘
0x4AA4C288
アドレス(の値)のメモリは次のintArray
ようになります。
0┌───────────────────┐
│4│-配列の長さ
4├───────────────────┤
│300│-`intArray[0]`
8├───────────────────┤
│301│-`intArray[1]`
12├───────────────────┤
│302│-`intArray[2]`
16├───────────────────┤
│303│-`intArray[3]`
20└───────────────────┘
intArray
これで、別の関数に渡した場合、スタックにプッシュされる値は、配列のコピーではなく0x4AA4C288
、配列のアドレスになります。