Вопрос

Я хотел что -то разъяснить.

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

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

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

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

https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/classes/nsautoreleasepool_class/reference/reference.html

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

Это имеет смысл для меня, но это под uikit, а не набор приложений. У меня вопрос: делает ли Uikit/Cocoa Touch то же самое в этом случае, или есть еще одно объяснение для выпуска моих объектов?

Спасибо!

Это было полезно?

Решение 2

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

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

Другие советы

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

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

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

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

Следующий код добавит 500 000 объектов в пул 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

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

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

Я бы предположил, что когда вы назначаете новый объект на ссылку, которая использовалась для удержания объекта, тогда Оригинальный объект выпущен сразу (Если ничто иное не указывает на это - refc -rece достигает нуля), используя дугу и по умолчанию по умолчанию 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

Яблоко отмечает в Переход к примечаниям по выпуску дуги

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

Звучит, что release вызывается на объект, когда ему присваивается новое значение, от Clang Clang 3.4 документация Objective-C Автоматическая справочная подсчет (ARC)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top