NSMutableString не указан в autoreleasepool с помощью _CFAutoreleasePoolPrintPools()

При включенном ARC (XCode 4.3.2, iOS 4.0) _CFAutoreleasePoolPrintPools() не печатает адрес токена ни в одном пуле. Я проверил, что токен высвобождается, как и ожидалось, после завершения пула, поэтому проблем нет, но что-то происходит за кулисами. Я подозреваю, что это может быть связано с objc_autoreleaseReturnValue.

@autoreleasepool {
    NSMutableString *token = [NSMutableString string];
    // When following line uncommented, 
    // **token** is listed in autorelease pool by _CFAutoreleasePoolPrintPools.
    //[token appendFormat:@"%@", @"xyz"];

    NSLog(@"%@", token);

}

Итак, разве _CFAutoreleasePoolPrintPools() не надежен? Как токен может быть выпущен автоматически, если он не указан ни в одном пуле автоматического выпуска?

Редактировать: Когда я наконец выяснил причину и определил, что она уже указана в списке, appendFormat не должен работать по-другому. Кажется, что при вызове appendFormat адреса памяти находились в диапазоне ([1..F]XXX XXXX), поэтому _CFAutoreleasePoolPrintPools точно перечисляет эти адреса, и я мог найти адрес при поиске.


person lockedscope    schedule 18.12.2013    source источник


Ответы (2)


Это магия objc_retainAutoreleaseReturnValue. Если автоматически выпущенный объект будет немедленно сохранен вызывающей стороной, то он не будет автоматически выпущен, поэтому он не будет отображаться в пуле автоматического выпуска. Я открыл окно помощника по сборке и увидел вызов objc_retainAutoreleaseReturnValue сразу после вызова obj_msgSend для вызова [строка NSMutableString].

См. эту запись в блоге для получения дополнительной информации. Он ссылается на комментарии в коде Apple, говорит:

objc_autoreleaseReturnValue() проверяет инструкции вызывающей стороны после возврата. Если инструкции вызывающей стороны немедленно вызывают objc_autoreleaseReturnValue, то вызываемая сторона опускает -autorelease и сохраняет результат в локальном хранилище потока. Если вызывающий не выглядит так, как будто он сотрудничает, то вызываемый вызывает -autorelease как обычно.

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

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

person Brian Walker    schedule 18.12.2013
comment
Я забыл упомянуть, что функция continueCount увеличивается с помощью objc_retainAutoreleasedReturnValue(), а значение continueCount равно 2 после того, как строка создается строковым методом. Я думаю, что [строка NSMutableString] возвращает автоматически выпущенную строку, поэтому objc_retainAutoreleasedReturnValue() сохраняет ее. - person lockedscope; 18.12.2013

Меня укусили крайние левые лишние нули в адресе памяти. Я напрямую копировал и искал адрес, возвращенный для токена. Экземпляр NSMutableString фактически отображается как __NSCFString в списке, возвращаемом функцией _CFAutoreleasePoolPrintPools().

(lldb) po token
(NSMutableString *) $1 = 0x[-->0<--]898e690

(lldb) po (NSString *)_CFAutoreleasePoolPrintPools()
...    
objc[731]: [0x82dc1a8]  ################  POOL 0x82dc1a8
objc[731]: [0x82dc1ac]         0x898e690  __NSCFString
person lockedscope    schedule 20.12.2013