2013-11-07 3 views
10

Я хотел получить что-то разъясненное.Пулы Autorelease и когда релиз называется под iOS

Допустим, у меня есть следующий код:

- (void) viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 
    for (int i = 0; i < 5000000; i++) { 
    NSString *s = [NSString stringWithFormat:@"Hello, %@!", @"World"]; 
    } 
} 

Это создаст 5 миллионов autoreleased строк в этом вызове функции. Я ожидал, что это сохранит эти объекты до окончания приложения, так как единственное @autoreleasepool, которое я вижу, - это тот, который обертывает экземпляр приложения в main.m. Однако это не так. В конце вызова этой функции кажется, что все они вызывают их освобождение и удаляются из памяти.

Этот документ:

https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html

государства, «Комплект приложений создает autorelease пул на главном потоке в начале каждого цикла цикла событий и водостоки его в конце, тем самым высвобождая любые автореализованные объекты, созданные при обработке события ».

Это имеет смысл для меня, но это под UIKit, а не Application Kit. Мой вопрос: делает ли UIKit/Cocoa Touch одно и то же в этом случае, или есть другое объяснение того, что мои объекты будут выпущены?

Спасибо!

ответ

7

Да, UIKit делает то же самое. Созданный системой пул авторесурсов основного потока сливается в конце каждого цикла цикла цикла. Вероятно, лучше не полагаться на эту точную жизнь в вашем собственном коде. Если вы создаете новый поток вручную (используя, например, NSThread), вы несете ответственность за создание пула автозапуска в этом потоке.

РЕДАКТИРОВАТЬ: Ответ Роба содержит дополнительную дополнительную информацию о поведении при ARC. В целом, справедливо сказать, что объекты с меньшей вероятностью попадают в пул авторезистов из-за некоторой оптимизации, которую может сделать ARC.

20

Andrew ответил на ваш главный вопрос: да, ваш пул авторефератов будет слит в каждом цикле основного цикла запуска. Таким образом, любые объекты авторекламы, созданные в viewDidLoad, могут быстро разрядиться, когда вы возвращаетесь к основному циклу запуска. Они, конечно же, не будут сохранены «до окончания подачи заявления».

Но мы должны быть осторожны: вы явно предполагаете, что эти объекты добавляются в пул автоопределений. Несколько предостережений к этому предположению:

  1. В прошлом (и по-прежнему необходимы для АРК-MRC взаимозаменяемости), при возврате объектов из методов, имена которых не начинаются с alloc, new, copy или mutableCopy, эти объекты будут авторезистентными объектами, освобожденными только тогда, когда пул авторесурсов был истощен (т. е. когда вы вернулись к циклу запуска).

  2. Но ARC получил умнее о минимизации потребности в autorelease бассейнов (см http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, в котором обсуждается callerAcceptsFastAutorelease, теперь называется callerAcceptsOptimizedReturn вызываемого prepareOptimizedReturn), так что вы часто не будете видеть это autorelease поведения. Таким образом, если и библиотека, и вызывающая сторона используют ARC, объекты не могут быть помещены в пул автозаполнения, но ARC будет умело выпускать их немедленно, если они не нужны.

    С современными проектами ARC, автореферационные бассейны, как правило, не нужны. Но в некоторых особых случаях все равно можно использовать пулы авторефератов. Я расскажу об одном из этих случаев ниже.

Рассмотрим следующий код:

#import "ViewController.h" 
#import <sys/kdebug_signpost.h> 

typedef enum : NSUInteger { 
    InnerLoop = 1, 
    MainLoop = 2 
} MySignPostCodes; 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"]; 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     kdebug_signpost_start(MainLoop, 0, 0, 0, 1); 
     for (int j = 0; j < 500; i++) { 
      NSData *data = [NSData dataWithContentsOfURL:fileURL]; 
      UIImage *image = [[UIImage alloc] initWithData:data]; 
      NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out 
      [NSThread sleepForTimeInterval:0.01]; 
     } 
     kdebug_signpost_end(MainLoop, 0, 0, 0, 1); 
    }); 
} 

@end 

Следующий код добавит 500000 объектов в autorelease пул, который будет осушенных только тогда, когда я уступаю обратно в цикл выполнения:

no pool

В этом случае вы можете использовать пул автоопределения, чтобы свести к минимуму знак высокой воды:

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"]; 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     kdebug_signpost_start(MainLoop, 0, 0, 0, 1); 
     for (int j = 0; j < 5; j++) { 
      @autoreleasepool { 
       kdebug_signpost_start(InnerLoop, 0, 0, 0, 2); 
       for (long i = 0; i < 100; i++) { 
        NSData *data = [NSData dataWithContentsOfURL:fileURL]; 
        UIImage *image = [[UIImage alloc] initWithData:data]; 
        NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out 
        [NSThread sleepForTimeInterval:0.01]; 
       } 
       kdebug_signpost_end(InnerLoop, 0, 0, 0, 2); 
      } 
     } 
     kdebug_signpost_end(MainLoop, 0, 0, 0, 1); 
    }); 
} 

@end 

pool

Нижняя линия, с ARC, это не всегда очевидно, когда он используется объект autorelease и когда он явно освобождает его, когда переменная выходит из области видимости. Вы всегда можете подтвердить это, изучив поведение в Инструментах.

Как бы в стороне, я бы с осторожностью относился к выработке слишком большого объема общих соображений управления памятью при использовании класса NSString, так как он был высоко оптимизирован и не всегда соответствует стандартным правилам управления памятью.

+0

«Следующий код добавит 500 000 объектов в пул автообновлений, которые будут только слиты, когда я вернусь к циклу запуска». Возможно, ARC немедленно выпустит его, как и второй код, возможно, с оптимизацией, на. – newacct

+0

Я выбрал [NSString stringWithFormat:], потому что я знаю, что возвращаемый объект вызвал авторекламу. Все это я знал ранее, за исключением пула вокруг каждого события, но спасибо за разъяснение. Надеюсь, это поможет кому-то другому, кто наткнулся на этот вопрос :) –

+0

если 'object = nil' удаляет исходный объект из памяти, то, возможно,' object = [MyObject myObject] 'удаляет исходный объект из памяти. Почему он будет храниться в авторекладе в ARC? – stefanB

0

Я бы предположил, что когда вы назначаете новый объект ссылке, используемой для хранения объекта, тогда исходный объект сразу же отпускается (если на него ничего не указывает - количество ссылок обращается в ноль) с использованием ARC и asuming по умолчанию strong ссылка как в примере вашего цикла.

MyObject *object = [[MyObject alloc] init]; // obj1, ref count 1 because strong 
object = [[MyObject alloc] init]; // obj2, ref count of obj1 should be 0 
            // so obj1 gets released 

Apple, отмечает в Transitioning to ARC Release Notes

Try, чтобы перестать думать о том, где сохранить/релиз вызовы подвергнутся и думать о своих алгоритмах приложений вместо этого. Подумайте о «сильных и слабых» указателях в ваших объектах, об объектной собственности и о возможных циклах сохранения.

Это звучит, что release вызывается на объект, когда ему присваивается новое значение, от лязга Clang 3.4 documentation OBJECTIVE-C AUTOMATIC REFERENCE COUNTING (ARC)

Назначение происходит при оценке оператора присваивания. Сеантика варьируется в зависимости от квалификации:

Для объектов __strong новый перманент сохраняется; во-вторых, lvalue загружается примитивной семантикой; в-третьих, новый указатель хранится в lvalue с примитивной семантикой; и, наконец, выпущен старый . Это не выполняется атомарно; внешняя синхронизация должна использоваться для обеспечения безопасности в случае одновременных нагрузок и хранилищ.

Смежные вопросы