NSMutableArray initWithCapacity nuances

2019-01-06 13:36发布

问题:

Does anyone have advice on how to best initialize an NSMutableArray when it comes to dictating the capacity? The documentation mentions that "...even though you specify a size when you create an array, the specified size is regarded as a “hint”; the actual size of the array is still 0." So...

1) If I init with a greater capacity than I typically use, do I not have to worry about wasted memory?

2) If I init with a capacity typically lower than what I use, do I have to worry about heavier processing time allocating more memory to hold the extra elements?

Just how impacting is this initialized capacity to the performance/memory usage of this data type?

回答1:

Whether any space is wasted by giving too big a capacity is actually an implementation detail that Apple deliberately doesn't expose, I guess. NSMutableArray is a class cluster which means you don't actually get an instance of NSMutableArray but some other, specialized class following the same interface. And Apple doesn't tell you which class gets returned in which case and how it's behaving. So it's hard to give real advices here.

If you really know that on average you'll need a capacity of X, just use it. Otherwise, unless you have performance problems I wouldn't care about the capacity at all and just use [NSMutableArray array]...



回答2:

Matt Gallagher has written a pretty informative article on Cocoa's collection classes, along with a couple of benchmarks (with & without initWithCapacity:, as well as cross class comparisons)

http://cocoawithlove.com/2008/08/nsarray-or-nsset-nsdictionary-or.html

His test (source available) for an NSMutableArray of length 1,000,000 took 0.582256sec without capacity and just 0.572139sec with capacity.

Test                                       | Time
[NSMutableArray array]                     | 0.582256 seconds
[NSMutableArray arrayWithCapacity:1000000] | 0.572139 seconds
Iterating contents                         | 0.004713 seconds

I'd say that in 99% of the use cases [NSMutableArray array] is just fine. If you do know the actual size of the resulting array, however, it won't hurt to use [NSMutableArray arrayWithCapacity:] either.


And then there is this article by Peter Ammon (who is a developer on Apple’s AppKit/Foundation team) featuring several insightful benchmarks:

http://ridiculousfish.com/blog/archives/2005/12/23/array/


Edit (March 12th 2012):

More insight on array initialization performance from http://darkdust.net/writings/objective-c/nsarray-enumeration-performance

[…] I [=>DarkDust] also wanted to know whether the performance is any different depending on how the array was created. I tested two different methods:

  • Create a C array which references the object instances and create the array using initWithObjects:count:.
  • Create a NSMutableArray and subsequently add objects using addObject:.

[…] there is a difference when allocating: the initWithObjects:count: method is faster. With a very large number of objects, this difference can become significant.


Edit (March 6th 2014):

Further more insight on array initialization performance from http://ciechanowski.me/blog/2014/03/05/exposing-nsmutablearray/:

Let’s allocate new arrays with initial capacity set to consecutive powers of two:

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

Surprise surprise:

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