(C#)泛型集合中存储的值类型在哪里

(C#)泛型集合中存储的值类型在哪里,c#,.net,types,generics,C#,.net,Types,Generics,对于值类型,泛型集合的性能确实优于非泛型集合。(即列表与阵列列表) 但除了拳击拆箱步骤之外,为什么会这样呢?一旦添加到集合中,值类型对象存储在哪里?在非泛型集合中,它们将被装箱并存储在堆上,泛型有什么不同?ArrayList是对存储在堆中的对象的引用的本地数组 引用类型的通用列表是对存储在堆中的对象的引用的本地数组 值类型的通用列表是这些值类型的本地数组 内存有两个区域,大多数引用称之为“堆栈”和“堆”。大多数使用这些术语的人都不知道为什么。(“堆栈”可能是堆栈,但堆几乎肯定不是堆)。我更喜欢“

对于值类型,泛型集合的性能确实优于非泛型集合。(即列表与阵列列表)


但除了拳击拆箱步骤之外,为什么会这样呢?一旦添加到集合中,值类型对象存储在哪里?在非泛型集合中,它们将被装箱并存储在堆上,泛型有什么不同?

ArrayList是对存储在堆中的对象的引用的本地数组

引用类型的通用列表是对存储在堆中的对象的引用的本地数组

值类型的通用列表是这些值类型的本地数组


内存有两个区域,大多数引用称之为“堆栈”和“堆”。大多数使用这些术语的人都不知道为什么。(“堆栈”可能是堆栈,但堆几乎肯定不是堆)。我更喜欢“这边”和“那边”这两个词。装箱时,值类型数据存储在“那边”。当存储在数组中(可能在泛型列表中)时,值类型数据存储在“此处”。“在这里”更好。

在泛型中,例如
List
,它们仍然存储在堆中。区别在于,在内部,
列表
生成一个整数数组,并可以直接存储数字。使用ArrayList,您最终将存储对装箱整数值的引用数组。

除了装箱和取消装箱之外,还有几个原因,包括内存缓存以及它们执行作业的枚举方式。查看。

与存储在非泛型等价物中的值类型相比,泛型中的性能提升通常仅与泛型中使用的值类型有关

这是因为对于泛型,值类型不需要强制转换为对象并存储在堆上(装箱)。事实上,它们可以保留在性能更好的堆栈上


相关的实现细节是
列表的底层存储是T[]。因此,对于
列表
而言,值将存储在int[]中。整数存储在从垃圾收集堆分配的连续内存块中


使它如此快速的原因不仅仅是整数没有装箱,还在于int[]与CPU缓存配合得非常好。当您读取第一个元素时,基本上可以免费获得下一个15,而无需读取慢速RAM或辅助缓存。这对于装箱的int来说效果不太好,因为它太大了,额外的引用可能具有很差的缓存局部性。然而,垃圾收集器通过压缩堆确实有助于降低成本。

“这边”-“那边”???什么????什么是“本地数组”?这个答案比任何东西都更令人困惑。@0xA3:本地数组是存储在“堆栈”中的数组。这样的措辞更具启发性吗?好吧,那么你的陈述是不正确的(如果你指的是常用意义上的堆栈)。
ArrayList
List
都使用System.Array作为内部存储器,它是一种引用类型,存储在“那边”。嗯。我觉得答案很清楚。我认为最后一条评论正好说明了为什么使用“堆”和“堆栈”这两个术语会令人困惑。实际上,数组将被分配到“堆”上,但真正的问题是,分配给存储数组每个元素的内存在哪里?在
列表中
中,存储值类型的内存位于为System.Array(即“此处”)分配的内存中。在ArrayList中,每个元素只是对装箱值类型的引用,因此存储每个值类型的实际内存位于“堆”的其他位置,即“在那里”的某个位置。对于相同数量的整数,sizeof(List)~=sizeof(int[])~=1/2 sizeof(x86上的ArrayList)~=1/3 sizeof(x86-64上的ArrayList)。此外,由于装箱,数据的局部性会占用ArrayList,并产生比必要的内存碎片更高的内存碎片。啊,唯一明确表示
List
实际上使用数组作为后备存储(而且放得也很好)。
列表
只是一个数组的包装器,它增加了对调整大小的支持,事实上几乎所有的集合类型都归结为数组,除了像
LinkedList
这样的特殊集合。因此
ArrayList
的性能受到双重打击。首先,必须从数组中取消对值的引用以获取对象(装箱值类型),然后必须取消装箱。但是,如果
ArrayList
的备份存储是
object[]
,则首先必须在数组中查找该项,这将为您提供一个对包含int的对象的引用。您必须取消对该对象的引用才能获得该对象,然后必须取消对该对象的装箱。将其与
列表
进行比较,在
列表中,您只需从
int[]
后台存储中抓取项目即可。@Jim,我认为您是对的,请在修改后指出取消引用的额外成本。