อาร์เรย์ของคุณได้รับการจัดสรรบนฮีปและ ints ไม่ได้อยู่ในกล่อง
ที่มาของความสับสนของคุณน่าจะเป็นเพราะมีคนบอกว่ามีการจัดสรรประเภทการอ้างอิงบนฮีปและประเภทค่าจะถูกจัดสรรบนสแต็ก นี่ไม่ใช่การนำเสนอที่ถูกต้องทั้งหมด
ตัวแปรโลคัลและพารามิเตอร์ทั้งหมดถูกจัดสรรบนสแตก ซึ่งรวมถึงประเภทค่าและประเภทการอ้างอิง ความแตกต่างระหว่างทั้งสองเป็นเพียงสิ่งที่เก็บไว้ในตัวแปรเท่านั้น ไม่น่าแปลกใจสำหรับประเภทค่าค่าของประเภทจะถูกเก็บไว้ในตัวแปรโดยตรงและสำหรับประเภทการอ้างอิงค่าของประเภทจะถูกเก็บไว้ในฮีปและการอ้างอิงถึงค่านี้คือสิ่งที่เก็บไว้ในตัวแปร
เช่นเดียวกันกับเขตข้อมูล เมื่อหน่วยความจำถูกจัดสรรสำหรับอินสแตนซ์ประเภทการรวม (a class
หรือ 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 ไบต์ในการจัดเก็บค่าฟิลด์นี้S
ใช้เวลา 4 ไบต์ในการจัดเก็บข้อมูลอ้างอิงและฟิลด์นี้L
จะใช้ 8 ไบต์ในการจัดเก็บค่า ดังนั้นหน่วยความจำสำหรับค่าของทั้งสองRefType
และValType
มีลักษณะดังนี้:
0 ┌───────────────────┐
│ฉัน│
4 ├───────────────────┤
│ S │
8 ├───────────────────┤
│ L │
││
16 └───────────────────┘
ตอนนี้ถ้าคุณมีสามตัวแปรท้องถิ่นในการทำงาน, ประเภท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 │ - สูง 32 บิตของ "valType.L`
20 ├───────────────────┤
│ 0x4AA4C288 │ - ที่อยู่ฮีปของʻintArray`
24 วินาที
หน่วยความจำที่อยู่0x4A963B68
(ค่าของrefType
) จะเป็นดังนี้:
0 ┌───────────────────┐
│ 100 │ - ค่าของ "refType.I`
4 ├───────────────────┤
│ 0x4A984D88 │ - ที่อยู่ฮีปของ "refType.S`
8 ├───────────────────┤
│ 0x89ABCDEF │ - ต่ำ 32 บิตของ "refType.L`
│ 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
ที่อยู่ของอาร์เรย์ไม่ใช่สำเนาของอาร์เรย์