我阅读了一些类似问题的答案,但由于我不理解书中有关此问题的陈述,我的问题没什么不同。
由于结构是值类型,因此每个实例都不需要 在堆上实例化对象;这样可以节省很多钱 创建类型的许多实例时。例如,创建一个 值类型数组仅需要单个堆分配。
我的意思是数组怎么可能只需要一个堆分配?...或者说单个堆分配是什么意思
答案 0 :(得分:5)
首先,让我们澄清一下“堆”与“堆”的含义。
当今大多数编程环境都是基于堆栈的。在运行程序时,每次调用方法时,都会将新条目推入为程序提供的特殊堆栈中。该堆栈条目(或框架)告诉系统在哪里查找方法的可执行代码,传递了哪些参数以及在方法退出后在调用代码中确切返回的位置。方法完成后,其条目将从堆栈中删除(弹出),因此程序可以返回到先前的方法。当堆栈为空时,程序已完成。
堆栈中的每个帧还为该方法的局部变量留有一定的空间,并且堆栈本身的大小有限。这就是“堆栈溢出”的来源。深入了解太多方法调用,堆栈将耗尽空间。
另一方面,堆是未自动授予程序的内存。它是程序必须超出其核心分配范围的内存。堆内存必须更仔细地管理,但是(通常)有更多可用空间。因为必须由操作系统根据请求授予它,所以从堆进行的初始分配也比从栈进行的分配慢。
作为广泛的概括,我们说引用类型是在堆上分配的,而值类型是在堆栈上分配的(尽管对此有很多例外)。
现在我们已经很了解了,我们可以开始研究数组了。
核心数组类型本身是引用类型。我的意思是,对于任何给定类型T
,T
可能(也可能不是)是一个值类型,但T[]
始终是引用类型。在“堆栈与堆”上下文中,这意味着即使T
是值类型,创建新数组也是堆分配。数组的大小也固定。单个堆分配将为数组中的所有元素创建足够的空间。
值类型的另一个功能是,根据成员,它们具有固定的大小。因此,对于数组,我们有固定数量的元素,每个元素的大小都已知。这些信息足以在单个堆分配中获取数组对象及其元素的所有空间。每个项目的 value 都保留在数组的核心内存中。
对于保存引用类型的数组,该数组的堆分配仅为引用创建空间。要填充数组,您必须为每个元素进行其他分配。
对于具有一个或多个引用类型成员的值类型,这可能会有些复杂。在这种情况下,将按常规分配值类型的空间,但是引用成员值的一部分仅是引用。仍然需要单独的分配才能为那些引用成员创建对象。
答案 1 :(得分:2)
数组本身就是引用类型,这意味着它是在托管堆上分配的。但是,如果它是一个值类型的数组,则一步就可以保留其大小所需的内存。让您拥有其中包含4个Int32的结构。
A struct4Int[1000] will allocate 16000 bytes in one step.
引用类型的数组将仅占用引用所需的内存(每项32位或64位,具体取决于要编译的体系结构)。假设其中包含4Int32的类。
A class4Int[1000] will allocate 4000 or 8000 bytes at first.
这些项目用引用的地址填充,该地址最初为空。
创建数组后,您将必须为引用类型的每个实例分配内存,并将其引用放入数组中(在堆上进行多次分配),在堆中再添加1000个小字节的16000个字节。