Нюансы NSMutableArray initWithCapacity

Есть ли у кого-нибудь совет о том, как лучше всего инициализировать NSMutableArray, когда дело доходит до определения емкости? В документации упоминается, что «... даже если вы указываете размер при создании массива, указанный размер рассматривается как «подсказка»; фактический размер массива по-прежнему равен 0». Так...

1) Если я инициализирую с большей емкостью, чем обычно, мне не нужно беспокоиться о потраченной впустую памяти?

2) Если я инициализирую с емкостью, как правило, меньшей, чем та, которую я использую, должен ли я беспокоиться о более длительном времени обработки, выделяющем больше памяти для хранения дополнительных элементов?

Насколько эта инициализированная емкость влияет на производительность/использование памяти для этого типа данных?


person Joey    schedule 16.10.2010    source источник


Ответы (2)


Полагаю, то, что какое-либо пространство тратится впустую из-за слишком большой емкости, на самом деле является деталью реализации, которую Apple намеренно не раскрывает. NSMutableArray — это кластер классов, что означает, что на самом деле вы получаете не экземпляр NSMutableArray, а какой-то другой специализированный класс, следующий тому же интерфейсу. И Apple не сообщает вам, какой класс возвращается в каком случае и как он себя ведет. Так что здесь трудно дать дельный совет.

Если вы действительно знаете, что в среднем вам потребуется емкость X, просто используйте ее. В противном случае, если у вас нет проблем с производительностью, я бы вообще не заботился о емкости и просто использовал бы [NSMutableArray array]...

person DarkDust    schedule 16.10.2010
comment
Но если вы знаете емкость, то зачем использовать изменяемый массив? Есть ли другие преимущества, кроме удаления/добавления объектов? - person Jesse Head; 29.07.2014
comment
Вы не всегда можете использовать неизменяемый массив, потому что добавляемые объекты не всегда известны заранее. Например, предположим, что вы хотите добавить числа 1…x в массив, но x является аргументом и, следовательно, неизвестен: вам придется добавлять числа в цикле. Конечно, вы можете также использовать массив C и -[NSArray initWithObjects:count:], но в большинстве случаев это слишком много работы. - person DarkDust; 29.07.2014
comment
На самом деле не ожидал ответа, спасибо, что нашли время! Отличная информация. - person Jesse Head; 29.07.2014

Мэтт Галлахер написал довольно информативную статью о классах коллекций 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:] тоже не помешает.


А еще есть статья Питера Аммона (который является разработчиком в команде Apple AppKit/Foundation), в которой представлены несколько полезных эталонных показателей:

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/exposed-nsmutablearray/:

Давайте разместим новые массивы с начальной емкостью, равной последовательным степеням двойки:

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

person Regexident    schedule 16.10.2010