4

我正在学习 C# 并且基本上知道数组和 s 之间的区别List,最后一个是通用的并且可以动态增长,但我想知道:

  • 元素是List按顺序位于类似数组的堆中,还是每个元素“随机”位于不同的位置?
  • 如果这是真的,这是否会影响访问速度和从内存中检索数据?
  • 如果这是真的,这就是使数组比Lists 快一点的原因吗?
4

2 回答 2

7

我们先来看第二个和第三个问题:

如果这是真的,那会影响从内存中访问和数据检索的速度吗?

如果这是真的,是什么让 array 比 list 快一点?

.NET 中只有一种类型的“本机”集合(对于 .NET,我指的是 CLR,因此是运行时):数组(从技术上讲,如果您考虑string一种类型的集合,那么有两种本机类型的集合:-) )(从技术上讲,第 2 部分:并非所有您认为是数组的数组都是“本机”数组......只有基于 0 的单维数组是“本机”数组。类型数组T[,]不是,第一个数组元素没有索引 0 are not) 。所有其他集合(除了LinkedList<>)都建立在它之上。如果你看一下List<T>withIlSpy你会发现在它的底部有T[]一个为 the 添加intCount(the T[].Lengthis the Capacity)。显然,数组比 a 快一点List<T>因为要使用它,你就少了一个间接性(你直接访问数组,而不是访问访问列表的数组)。

我们来看第一个问题:

列表元素是否顺序位于堆中的数组或每个元素随机位于不同的位置?

在内部基于数组,显然List<>它像数组一样记住它的元素,所以在一个连续的内存块中(但请注意,对于List<SomeObject>whereSomeObject是引用类型,列表是引用列表,而不是对象列表,所以引用被放在一个连续的内存块中(我们将忽略计算机的高级内存管理,“连续的内存块”这个词并不准确”,最好说“一个连续的地址块”) )

(是的,甚至Dictionary<>HashSet<>构建在数组之上。相反,可以在不使用数组的情况下构建树状集合,因为它更类似于 a LinkedList

CIL一些额外的细节:该语言(编译的 .NET 程序中使用的中间语言)中有四组指令与“本机”数组一起使用:

  • Newarr

  • Ldelem和家人Ldelem_*

  • Stelem和家人Stelem_*

  • ReadOnly(别问我它的用途,我不知道,文档也不清楚)

如果你看一下,OpCodes.Newarr你会在 XML 文档中看到这条评论:

// Summary:
//     Pushes an object reference to a new zero-based, one-dimensional array whose
//     elements are of a specific type onto the evaluation stack.
于 2013-08-11T10:56:07.180 回答
5

是的,List 中的元素是连续存储的,就像数组一样。List 实际上在内部使用数组,但这是一个您不需要真正关心的实现细节。

当然,为了从该陈述中获得正确的印象,您还必须了解一点 .NET 中的内存管理。即值类型和引用类型之间的区别,以及这些类型的对象是如何存储的。值类型将存储在连续的内存中。对于引用类型,引用将存储在连续的内存中,而不是实例本身。

使用 List 的优点是类内部的逻辑为您处理分配和管理项目。您可以在任何地方添加元素,从任何地方删除元素,并增加集合的整个大小,而无需做任何额外的工作。当然,这也是 List 比数组稍慢的原因。如果为了满足您的请求而必须进行任何重新分配,则会在分配一个新的、更大尺寸的数组并将元素复制到其中时对性能造成影响。但这不会比您编写代码以使用原始数组手动执行要慢。

如果您的长度要求是固定的(即,您永远不需要增加/扩展数组的总容量),您可以继续使用原始数组。它甚至可能比 List 稍微快一点,因为它避免了额外的开销和间接性(尽管这会被 JIT 编译器优化)。

如果您需要能够动态调整集合的大小,或者您需要 List 类提供的任何其他功能,只需使用 List。性能差异几乎无法察觉。

于 2013-08-11T10:57:37.947 回答