Нюансы NSMutableArray initWithCapacity
Есть ли у кого-нибудь совет, как лучше всего инициализировать NSMutableArray, когда дело доходит до диктовки емкости? В документации упоминается, что "... хотя вы указываете размер при создании массива, указанный размер считается" подсказкой ", фактический размер массива равен 0." Так что...
1) Если я инициализирую большую емкость, чем обычно использую, мне не нужно беспокоиться о потерянной памяти?
2) Если я инициализируюсь с пропускной способностью, как правило, ниже, чем я использую, мне нужно беспокоиться о более тяжелом времени обработки, выделяя больше памяти для хранения дополнительных элементов?
Насколько влияет эта инициализированная производительность на производительность/использование памяти этого типа данных?
Ответы
Ответ 1
Является ли какое-либо пространство впустую, давая слишком большую емкость, на самом деле представляет собой деталь реализации, которую Apple намеренно не раскрывает. NSMutableArray - кластер классов, который означает, что вы фактически не получаете экземпляр NSMutableArray, а некоторый другой специализированный класс, следуя одному и тому же интерфейсу. И Apple не говорит вам, какой класс возвращается в этом случае и как он себя ведет. Так что трудно дать настоящие советы здесь.
Если вы действительно знаете, что в среднем вам понадобится емкость X, просто используйте его. В противном случае, если у вас нет проблем с производительностью, мне все равно будет не нужна емкость и просто используйте [NSMutableArray array]
...
Ответ 2
Мэтт Галлахер написал довольно информативную статью о классах коллекции Cocoa, а также пару тестов (с и без initWithCapacity:
, а также сравнение между классами)
http://cocoawithlove.com/2008/08/nsarray-or-nsset-nsdictionary-or.html
Его тест (источник доступен) для NSMutableArray длиной 1,000,000 взял 0,582256 сек без емкости и просто 0,572139 сек с емкостью.
Test | Time
[NSMutableArray array] | 0.582256 seconds
[NSMutableArray arrayWithCapacity:1000000] | 0.572139 seconds
Iterating contents | 0.004713 seconds
Я бы сказал, что в 99% случаев использования [NSMutableArray array]
просто отлично. Однако, если вы действительно знаете фактический размер результирующего массива, это не помешает использовать [NSMutableArray arrayWithCapacity:]
.
И вот эта статья от Peter Ammon (который является разработчиком в Apples AppKit/Foundation team), демонстрируя несколько проницательных тестов:
http://ridiculousfish.com/blog/archives/2005/12/23/array/
Изменить (12 марта 2012 года):
Дополнительная информация о производительности инициализации массива из http://darkdust.net/writings/objective-c/nsarray-enumeration-performance
[...] я [= > DarkDust] также хотел узнать, отличается ли производительность в зависимости от того, как был создан массив. Я протестировал два разных метода:
- Создайте массив C, который ссылается на экземпляры объекта и создает массив с помощью
initWithObjects:count:
. - Создайте
NSMutableArray
и затем добавьте объекты, используя addObject:
.
[...] есть разница при распределении: метод initWithObjects:count:
быстрее. При очень большом числе объектов эта разница может стать значимой.
Изменить (6 марта 2014 года):
Дальнейшее понимание производительности инициализации массива из http://ciechanowski.me/blog/2014/03/05/exposing-nsmutablearray/:
Позволяет выделять новые массивы с начальной пропускной способностью, установленной на две последовательные мощности:
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