首页 > 解决方案 > 如何在堆中分配值类型数组?

问题描述

我阅读了一些类似问题的答案,但我的问题略有不同,因为我不理解书中关于此问题的陈述。

因为结构是值类型,每个实例不需要在堆上实例化对象;当创建一个类型的许多实例时,这会带来有用的节省。例如,创建一个值类型的数组只需要一次堆分配。

我的意思是数组如何只需要一个堆分配?...或者单个堆分配是什么意思

标签: c#arraysstructheap-memoryvalue-type

解决方案


首先,让我们澄清一下“堆”与“堆栈”的含义。

今天的大多数编程环境都是基于堆栈的。运行程序时,每次调用方法时,都会将新条目推送到为程序提供的特殊堆栈中。这个堆栈条目(或帧)告诉系统在哪里寻找方法的可执行代码,传递了哪些参数,以及方法退出后调用代码中返回的确切位置。当一个方法完成时,它的条目会从堆栈中移除(弹出),因此程序可以返回到前一个方法。当堆栈为空时,程序结束。

堆栈上的每一帧也有一定的空间用于方法的局部变量,而堆栈本身的大小是有限的。这就是“堆栈溢出”的来源。获取太多的方法调用太深,堆栈将耗尽空间。

另一方面,堆是不会自动授予程序的内存。这是程序必须在其核心分配之外请求的内存。堆内存必须更仔细地管理,但(通常)还有更多可用空间。因为它必须由操作系统根据请求授予,所以来自堆的初始分配也比来自堆栈的分配慢一点。

作为一个广泛的概括,我们说引用类型在堆上分配,而值类型在堆栈上分配(尽管有很多例外)。

现在我们了解了这么多,我们可以开始看数组了。

核心数组类型本身是一个引用类型。我的意思是,对于任何给定的 type TT可能(或可能不是)值类型,但T[]始终是引用类型。在“堆栈与堆”上下文中,这意味着创建一个新数组是一个堆分配,即使T是一个值类型。数组也有固定的大小。该单一堆分配将为数组中的所有元素创建足够的空间。

值类型的另一个特性是它们具有基于成员的固定大小。所以对于一个数组,我们有固定数量的元素,每个元素都有一个已知的固定大小。这足以获取数组对象的所有空间,并且它是单个堆分配中的元素。每个项目的都保存在数组的核心内存中。

对于保存引用类型的数组,数组的堆分配只为引用创建空间。要填充数组,您必须为每个元素进行额外分配。

这可能会因具有一个或多个引用类型成员的值类型而稍微复杂化。在这种情况下,值类型的空间是正常分配的,但引用成员的值部分只是一个引用。它仍然需要单独的分配来为这些引用成员创建对象。


推荐阅读