Swift array.capacity 对比 array.count

Swift array.capacity vs array.count

我了解 array.count(数组中元素的数量)。 count 对于遍历数组的元素很有用。我有点明白 array.capacity

的要点

capacity An integer value that represents how many total elements the array can store without reallocation (read-only).

实验

我一直在玩 Playground 并注意到数组的容量是偶数(递增 2)

var arr = [1, 2, 3 , 4, 5, 6, 7]
arr.removeLast() // capacity stays the same after a removal
println(arr.capacity) // 8
println(arr.count)    // 6

var arr = [1, 2, 3 , 4, 5, 6]
arr.removeLast()
println(arr.capacity) // 6
println(arr.count)    // 5

问题

数组容量有什么用?请举个具体例子?

What is the use of an array capacity

基本上,数组容量没有外用。它供 Swift 内部使用。如果您知道要为这个数组分配 100 个对象,您可以可以 在创建数组时提前设置容量,我看到有些人在他们的代码中这样做;但是没有特别的 需要 这样做,也没有特别的 gain 这样做。您已经深入了解并看到了您并不真正需要看到的东西。既然看过了,那就算了。

数组的容量——特别是它的 reserveCapacity 方法——可以让你在数组中预分配 space。

如果您向数组添加元素,并且超出了它的容量,那么数组必须增加它的容量。由于 Swift 数组将其元素连续存储在内存中,因此它必须重新分配其内部存储空间并(通常)将其所有元素从旧存储空间复制到新存储空间。 (请注意,NSArray 未记录为连续存储其元素,但我们可以推断 Swift 数组可能基于 withUnsafeMutableBufferPointer 方法的存在。)

如果预先知道要给数组添加多少个元素,可以用reserveCapacity方法预先设置数组的容量,这样就赢了不需要执行任何重新分配(和相关的复制)。

我能想到的询问数组容量的唯一原因是了解系统如何工作,以及调试性能问题。

通常您不需要担心保留容量。重新分配很少是性能问题。 Swift 使用(我相信)一个有效的重新分配计划,以便重新分配的数量在数组的最终计数中是对数的。例如。如果您一次添加一百万个元素,Swift 应该执行不超过 20-30 次重新分配。

但是如果您知道您的数组将非常大(例如 Mac 上的千兆字节或 iOS 设备上的数十兆字节),或者如果您要在表演中填充数组- 敏感的代码路径(例如填充将在微秒内开始播放的音频缓冲区),您可能希望保留容量并避免重新分配。

除非您知道重新分配是一个问题,否则您可能不必担心保留容量,因为分析器显示它们是瓶颈,或者因为您有其他证据(例如音频缓冲区示例中的音频故障)。

数组可以包含的元素总数

正在分配新存储空间。

每个数组都保留一定数量的内存来保存其内容。当您向数组添加元素并且该数组开始超出其保留容量时,该数组会分配更大的内存区域并将其元素复制到新存储中。新存储是旧存储大小的倍数。这种指数增长策略意味着附加元素发生在恒定时间内,平均许多附加操作的性能。触发重新分配的附加操作具有性能成本,但随着数组变大,它们发生的频率越来越低。

以下示例从数组文字创建一个整数数组,然后附加另一个集合的元素。在追加之前,数组会分配足够大的新存储空间来存储结果元素。

var numbers = [10, 20, 30, 40, 50]

numbers.count == 5

numbers.capacity == 5

numbers.append(contentsOf: stride(from: 60, through: 100, by: 10))

numbers.count == 10

numbers.capacity == 12