int[] myIntegers; myIntegers = new int[100];
在上面的代码中,是否是new int [100]在堆上生成数组?根据我通过c#进行的CLR阅读,答案是肯定的。但是我不明白的是,数组内部的实际int发生了什么。因为它们是值类型,所以我猜想它们必须装箱,例如,我可以将myIntegers传递给程序的其他部分,如果一直将它们留在程序中,则会使堆栈混乱。还是我错了?我猜想它们会被装箱,并且只要数组存在就可以在堆中生存。
您的数组分配在堆上,并且没有将int装箱。
造成混淆的原因很可能是因为人们曾说过,引用类型是在堆上分配的,而值类型是在堆栈上分配的。这不是一个完全准确的表示。
所有局部变量和参数都分配在堆栈上。这包括值类型和引用类型。两者之间的区别仅在于变量中 存储 的内容。毫不奇怪,对于值类型,该类型的 值 直接存储在变量中,对于引用类型,该类型的值存储在堆中,对此值的 引用 就是存储在变量中的值。
字段也是如此。当为聚合类型(a class或a struct)的实例分配内存时,它必须包括其每个实例字段的存储。对于引用类型的字段,此存储仅保存对该值的引用,该引用本身将在以后分配给堆。对于值类型字段,此存储保存实际值。
class
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看起来像这样:
I
S
L
RefType
ValType
0┌──────────────┐ │我│ 4├───────────────┤ │S│ 8├──────────────┤ │L│ ││ 16└──────────────┘
现在,如果你在一个函数中有三个局部变量,类型RefType,ValType和int[],就像这样:
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)将类似于:
0x4A963B68
refType
0┌──────────────┐ │100│-`refType.I`的值 4├───────────────┤ │0x4A984D88│-`refType.S`的堆地址 8├──────────────┤ │0x89ABCDEF│-`refType.L`的低32位 │0x01234567│-`refType.L`的高32位 16└──────────────┘
地址处的内存0x4AA4C288(值为intArray)将类似于:
0x4AA4C288
intArray
0┌──────────────┐ │4│-数组长度 4├───────────────┤ │300│-`intArray [0]` 8├──────────────┤ │301│-`intArray [1]` 12├──────────────┤ │302│-`intArray [2]` 16├─────────────┤ │303│-`intArray [3]` 20└──────────────┘
现在,如果您传递intArray给另一个函数,则压入堆栈的值将是0x4AA4C288数组的地址, 而不是 数组的副本。