如何理解数组、堆和堆栈以及值类型?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (15)
int[] myIntegers;
myIntegers = new int[100];

根据我在CLR上通过c#所读到的,答案是肯定的。但我不明白的是,数组中的实际int会发生什么。由于它们是值类型,我猜它们必须被装箱,例如,我可以将myIntegers传递给程序的其他部分,如果它们一直留在程序中,堆栈就会变得混乱。

提问于
用户回答回答于

您的数组在堆上分配,而INT没有装箱。

因此,考虑到以下类型:

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个字节。因此,内存的值都是RefTypeValType看起来是这样的:

 0 ┌───────────────────┐
   │        I          │
 4 ├───────────────────┤
   │        S          │
 8 ├───────────────────┤
   │        L          │
   │                   │
16 └───────────────────┘

现在,如果函数中有三个局部变量,类型为RefTypeValType,和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     │ -- heap address of `refType`
 4 ├───────────────────┤
   │       200         │ -- value of `valType.I`
   │    0x4A984C10     │ -- heap address of `valType.S`
   │    0x44556677     │ -- low 32-bits of `valType.L`
   │    0x00112233     │ -- high 32-bits of `valType.L`
20 ├───────────────────┤
   │    0x4AA4C288     │ -- heap address of `intArray`
24 └───────────────────┘

地址0x4A963B68的内存(值为refType)是这样的:

 0 ┌───────────────────┐
   │       100         │ -- value of `refType.I`
 4 ├───────────────────┤
   │    0x4A984D88     │ -- heap address of `refType.S`
 8 ├───────────────────┤
   │    0x89ABCDEF     │ -- low 32-bits of `refType.L`
   │    0x01234567     │ -- high 32-bits of `refType.L`
16 └───────────────────┘

地址0x4AA4C288的内存(值为intArray)是这样的:

 0 ┌───────────────────┐
   │        4          │ -- length of array
 4 ├───────────────────┤
   │       300         │ -- `intArray[0]`
 8 ├───────────────────┤
   │       301         │ -- `intArray[1]`
12 ├───────────────────┤
   │       302         │ -- `intArray[2]`
16 ├───────────────────┤
   │       303         │ -- `intArray[3]`
20 └───────────────────┘

如果你过去了intArray对于另一个函数,推到堆栈上的值将是0x4AA4C288,该数组的地址,数组的副本。

用户回答回答于

不加框:

int i = 42;
myIntegers[0] = 42;

加框:

object i = 42;
object[] arr = new object[10];  // no boxing here 
arr[0] = 42;

扫码关注云+社区