Я работаю над приложением для iPad, в котором есть процесс синхронизации, использующий веб-сервисы и Core Data в тесном цикле. Чтобы уменьшить объем памяти в соответствии с Рекомендация Apple , я периодически выделяю и истощаю NSAutoreleasePool
. В настоящее время это прекрасно работает, и у текущего приложения нет проблем с памятью. Тем не менее, я планирую перейти на ARC, где NSAutoreleasePool
больше не действителен и хотел бы сохранить такой же вид производительности. Я создал несколько примеров и рассчитал их время, и Мне интересно, как лучше всего использовать ARC для достижения такой же производительности и поддержания читабельности кода .
В целях тестирования я предложил 3 сценария, каждый из которых создает строку, используя число от 1 до 10 000 000. Я запускал каждый пример 3 раза, чтобы определить, сколько времени они заняли, используя 64-битное приложение Mac с компилятором Apple LLVM 3.0 (без gdb -O0) и XCode 4.2. Я также проверил каждый пример с помощью инструментов, чтобы примерно увидеть, какой был пик памяти.
Каждый из приведенных ниже примеров содержится в следующем блоке кода:
int main (int argc, const char * argv[])
{
@autoreleasepool {
NSDate *now = [NSDate date];
//Code Example ...
NSTimeInterval interval = [now timeIntervalSinceNow];
printf("Duration: %f\n", interval);
}
}
NSAutoreleasePool Batch [Оригинальный предварительный ARC] (Пиковая память: ~ 116 КБ)
static const NSUInteger BATCH_SIZE = 1500;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
if((count + 1) % BATCH_SIZE == 0)
{
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool drain];
Время выполнения:
10.928158
10.912849
11.084716
Внешний @autoreleasepool (Пиковая память: ~ 382 МБ)
@autoreleasepool {
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
}
}
Время выполнения:
11.489350
11.310462
11.344662
Внутренний @autoreleasepool (Пиковая память: ~ 61,2 КБ)
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
@autoreleasepool {
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
}
}
Время выполнения:
14.031112
14.284014
14.099625
@ autoreleasepool w / goto (Пиковая память: ~ 115 КБ)
static const NSUInteger BATCH_SIZE = 1500;
uint32_t count = 0;
next_batch:
@autoreleasepool {
for(;count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
if((count + 1) % BATCH_SIZE == 0)
{
count++; //Increment count manually
goto next_batch;
}
}
}
Время выполнения:
10.908756
10.960189
11.018382
Оператор goto
показал наибольшую производительность, но он использует goto
. Есть мысли?
Обновление:
Примечание. Оператор goto
является нормальным завершением для @autoreleasepool, как указано в документации , и не приводит к утечке памяти.
При входе пул авто-релиза выдвигается. На нормальном выходе (перерыв,
return, goto, fall-through и т. д.) пул авто-релизов выталкивается.
Для совместимости с существующим кодом, если выход вызван исключением,
пул автозапуска не выталкивается.