【问题标题】:How much does it matter if I create a NSMutableArray with capacity=3 instead of capacity=50?如果我创建一个容量 = 3 而不是容量 = 50 的 NSMutableArray 有多大关系?
【发布时间】:2026-01-11 21:45:01
【问题描述】:

我想知道这是否会影响性能或内存消耗。我需要一个 NSMutableArray,一开始我只能猜测会添加多少对象。大概3到5个吧。所以我这样创建它:

NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:3];

例如,当使用 3 而不是 50 的容量创建它时,究竟会发生什么?当知道至少有 20 个元素时,以 1 的容量创建它是不是一个坏主意?或者这还不足以让人头疼吗?我的应用程序中有 10 个这样的数组,它们都必须在开始时加载。

【问题讨论】:

    标签: iphone cocoa-touch arrays uikit


    【解决方案1】:

    initWithCapacity 将导致NSMutableArray 为该数量的元素预分配空间。

    将更多数据推入您的NSMutableArray 超出该容量将导致NSMutableArray 重新分配其底层内存。这种重新分配还需要将整个数组从旧的(较小的)分配复制到新的(较大的)分配中。因此,将这个数字设置得太小会导致性能损失,但不会太大。

    指定的容量大于您实际使用的容量会浪费内存,因为会为永远不会使用的项目分配内存。

    我的建议是,如果您知道数组的大小通常不会超过 N 个项目,请致电 initWithCapacity:N。偶尔出现大于 N 的 NSMutableArray 的性能损失是可以接受的,对于那些未超过该限制的数组,您无需为此付出代价。

    【讨论】:

    • 详细信息!其他答案也很棒。发现选择一个被接受的人从未如此困难。都投了赞成票。谢谢大家!
    • 恕我直言,我认为这个答案是不正确的。尽管容量在某些情况下用于提示,但创建一个千兆字节容量的可变数组并不会立即分配千兆字节的内存。如果你不相信我,你自己试试。 NSMutableArray *bigArray = [[NSMutableArray alloc] initWithCapacity:1024*1024*1024]; if (!bigArray) { NSLog(@"数组没有创建!"); } else { NSLog(@"是的,它被创建了。");如果你真的填充这个数组,你会看到内存使用量增加。以前没有。
    • initWithCapacity 的文档指出,它返回“一个初始化为具有足够内存以容纳 numItems 个对象的数组”。彼得布观察到的内容与文档声称的内容之间似乎存在一些差异。
    • 这对于测试和测量来说是微不足道的。试一试,让我们知道你发现了什么。我坚持我的主张。
    • 我并不是要暗示我不同意你的观点或认为你的实验在某种程度上是无效的。在软件中,文档与实现不同的情况并不少见,它们在哪里做才是真正重要的代码。
    【解决方案2】:

    这没什么大不了的,除非您谈论的是极端重复或庞大的数组。除非它成为真正的瓶颈,否则不值得尝试优化。

    编辑:我想引用 Donald Knuth 的一句话:

    过早的优化是万恶之源。

    【讨论】:

    • 早产是什么意思?我的英语不是很好;-) 请解释一下。谢谢!
    • 这意味着:不要优化代码的性能,除非你 a) 真的需要它运行得更快并且 b) 识别慢的部分。否则,你只会让你的代码更复杂,增加复杂性和花费时间而没有任何好处。
    【解决方案3】:

    有理论答案和实际答案。理论上,设置更大的容量可能会改变数组的分配和存储策略(虽然内部称为“NSArray”,但结构比这要复杂一些)。

    从实际的角度来看,数组将根据需要重新分配,并且对于您所说的数字,我怀疑会有任何区别。如果我知道要放入成千上万个项目,我可能会做一个 arrayWithCapacity。3 与 50 基本上没有意义。

    从我的角度来看,“withCapacity”的最佳用途只是提供一个明显的挂钩来挂起您的假设,因此您可以(例如)拥有稍后可能想要断言的内容的代码内文档。但这绝不是必需的。

    从实际的角度来看,最好的利用时间就是不去想这个问题。

    【讨论】:

      【解决方案4】:

      虽然像这里提到的其他人一样使用 initWithCapacity: 绝对没有坏处,但您应该查看 Bartosz Ciechanowski 的 this research 数组初始化性能:

      初始容量几乎无关紧要

      让我们分配初始容量设置为 2 的连续幂的新数组:

      for (int i = 0; i < 16; i++) {
          NSLog(@"%@", [[[NSMutableArray alloc] initWithCapacity:1 << i] explored_description]);
      }
      

      惊喜:

      size:  2 // requested capacity:   1
      size:  2 // requested capacity:   2
      size:  4 // requested capacity:   4
      size:  8 // requested capacity:   8
      size: 16 // requested capacity:  16
      size: 16 // requested capacity:  32
      size: 16 // requested capacity:  64
      size: 16 // requested capacity: 128
      ...
      // 'size: 16' all the way down
      

      【讨论】:

        【解决方案5】:

        可以检查这个问题:What is the advantage of using arrayWithCapacity


        这种能力有助于将代码理解为隐式文档的一部分。 并且在初始化 NSArray 时,指定预期计数在性能上没有差异 - 测量的时间几乎相等并且在统计不确定性范围内。

        根据 objc.io :https://www.objc.io/issues/7-foundation/collections/


        可变数组根据需要扩展; numItems 只是建立对象的初始容量。

        Apple 文档讨论没有得到鼓励。

        https://developer.apple.com/documentation/foundation/nsmutablearray/1415811-initwithcapacity?language=objc

        【讨论】:

          最近更新 更多