如何在堆中分配值类型数组?
Posted
技术标签:
【中文标题】如何在堆中分配值类型数组?【英文标题】:How is value type array allocated in a heap? 【发布时间】:2019-02-24 21:44:54 【问题描述】:我阅读了一些类似问题的答案,但我的问题略有不同,因为我不理解书中关于此问题的陈述。
因为结构体是值类型,所以每个实例不需要 堆上对象的实例化;这会带来有用的节省 在创建一个类型的许多实例时。例如,创建一个 值类型的数组只需要一个堆分配。
我的意思是数组如何只需要一个堆分配?...或者说单个堆分配是什么意思
【问题讨论】:
您在该声明中具体有哪些不明白的地方? 数组只是堆上的一块内存。如果它包含一个值类型,那么这就是那个内存块中的内容。如果它有引用类型,那么那些指向堆中其他位置的对象。 我的意思是数组如何只需要单个堆分配?...或者单个堆分配是什么意思 “单个 hep 分配”是指堆上的单个连续内存块。 你熟悉C还是C++? 【参考方案1】:首先,让我们澄清一下“堆”与“堆栈”的含义。
当今的大多数编程环境都是基于堆栈的。运行程序时,每次调用方法时,都会将新条目推送到为程序提供的特殊堆栈中。这个堆栈条目(或帧)告诉系统在哪里寻找方法的可执行代码,传递了哪些参数,以及方法退出后调用代码中返回的确切位置。当一个方法完成时,它的条目会从堆栈中移除(弹出),因此程序可以返回到前一个方法。当堆栈为空时,程序结束。
堆栈上的每一帧也有一定的空间用于方法的局部变量,堆栈本身的大小是有限的。这就是“堆栈溢出”的来源。方法调用过深,栈空间不足。
另一方面,堆是不会自动授予程序的内存。它是程序必须在其核心分配之外请求的内存。堆内存必须更仔细地管理,但(通常)还有更多可用空间。因为它必须由操作系统根据请求授予,所以来自堆的初始分配也比来自堆栈的分配慢一些。
作为一个广义的概括,我们说引用类型在堆上分配,而值类型在堆栈上分配(尽管有很多例外)。
现在我们了解了这么多,我们可以开始看数组了。
核心数组类型本身是一个引用类型。我的意思是,对于任何给定类型T
,T
可能(或可能不是)值类型,但@ 987654324@ 始终是引用类型。在“堆栈与堆”上下文中,这意味着创建一个新数组是一个堆分配,即使T
是一个值类型。数组也有固定的大小。该单一堆分配将为数组中的所有元素创建足够的空间。
值类型的另一个特性是它们具有基于成员的固定大小。所以对于一个数组,我们有固定数量的元素,每个元素都有一个已知的固定大小。这些信息足以在单个堆分配中为数组对象 及其元素 获取所有空间。每个项目的 值 都保存在数组的核心内存中。
对于保存引用类型的数组,数组的堆分配只为引用创建空间。要填充数组,您必须为每个元素进行额外分配。
对于具有一个或多个引用类型成员的值类型,这可能会稍微复杂一些。在这种情况下,值类型的空间是正常分配的,但引用成员的值部分只是一个引用。它仍然需要单独分配来为这些引用成员创建对象。
【讨论】:
不知道为什么这被否决了。如果有人认为我对这些概念的理解有缺陷,我很乐意纠正它。 我不是反对者。虽然我喜欢你的回答,但我建议你添加一个指向 Eric Lippert 的关于值类型与引用类型的博客的链接,你说“尽管有很多例外”。 blogs.msdn.microsoft.com/ericlippert/2010/09/30/… @Joel Coehoorn 非常感谢您的回答。这么透彻的解释。我明白你在解释什么。 @Jim Mischel,感谢您的链接,我也会通过它。【参考方案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.
item 用引用的地址填充,初始为空。
创建数组后,您必须为引用类型的每个实例分配内存并将其引用放入数组中(堆上的多个分配),在堆上以 1000 个小块再添加 16000 个字节。
【讨论】:
以上是关于如何在堆中分配值类型数组?的主要内容,如果未能解决你的问题,请参考以下文章