Как определить, находится ли объект в NSAutoreleasePool - PullRequest
8 голосов
/ 22 сентября 2011

Я хотел бы знать, сколько раз объект был автоматически выпущен.Я использовал цель c достаточно долго, чтобы узнать, был ли объект автоматически освобожден или нет, как правило, довольно просто, однако я постоянно вижу вопросы, связанные с памятью, и сохраняю количество.В какой-то момент ответ всегда заканчивается: «Вы не можете доверять retainCount объекта» - с этим я согласен, НО, если бы вы могли определить, сколько раз объект был автоматически выпущен, тогда вы на самом деле могли бы доверять retainCount, если вы добавили такую ​​категорию, как:

@interface NSObject (NSObject_MemoryDebugging)
- (NSUInteger) autoReleaseCount;
- (NSUInteger) retainCountWithAutoRelease;
@end

@implementation]
/** Determine how many times this object has been marked for autorelease **/
- (NSUInteger) autoReleaseCount;
{
   // ??? not sure how to figure this out.
   return 0;
}

 - (NSUInteger) retainCountWithAutoRelease
{
   NSUInteger retainCount = [self retainCount];
   NSUInteger autoReleaseCount = [self getAutoReleaseCount];  // ???
   return retainCount - autoReleaseCount;
}
@end

По-прежнему будет исключение для неизменяемых типов, поскольку они обычно увеличивают количество сохраняемых файлов во время копирования, поэтому вы по-прежнему не можете доверять retainCountна тех.

Что я НЕ предлагаю

Я не ищу этот ответ, чтобы использовать retainCount в производственном коде.Тем не менее, я вижу, что это полезно для кого-то, чтобы отладить проблемы с памятью.

Я предполагаю, что некоторые люди ненавидят этот вопрос, так как программистам не нужно заботиться о том, сколько раз объект был выпущен автоматически.Кодирование должно быть связано с балансировкой ассигнований, сохранением, копированием, новым выпуском, окончанием историиТем не менее, смысл этого в том, чтобы помочь людям, стучащим головой.[NSObject retainCount] сжигает много людей, и ответ на этот вопрос был бы довольно клевым.

Я уверен, что есть способ определить, сколько раз объект был выпущен автоматически.Я просто не знаю, что это, поэтому вопрос.

См. Аналогичный вопрос: Объекты внутри NSAutoreleasePool в target-c .

Редактировать


Спасибо всем за ваши ответы.Вы можете найти это интересным => Ариэль отметил, что реализация Какао в GNUStep и, в частности, NSAutoReleasePool имеет такой метод: + (NSUInteger) autoreleaseCountForObject: (id) anObject .Этот метод медленный и возвращает только счет автоматического выпуска из NSAutoReleasePools в потоке вызывающих.Тем не менее ... Интересно, что его там.В документах говорится, что это действительно полезно только для отладки.Это действительно то, что я надеялся найти (или найти возможным) как-то в среде Какао.

Я согласен с ответами, данными, что, даже если бы было возможно получить счет автоматического выпуска, что существуют лучшие инструменты (Зомби,Утечки, статический анализатор).

Ответы [ 4 ]

7 голосов
/ 22 сентября 2011

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

Во-вторых, это не (просто) NSAutoreleasePool, что делает -retainCountненадежный.Проблема в том, что всевозможные объекты, как ваши, так и Apple, сохраняют вещи по разным причинам, самые неизвестные для вас.Даже с учетом автоматического выпуска, у ваших объектов часто не будет ожидаемого количества сохраняемых данных, потому что за кадром что-то наблюдает за этим или временно помещает его в словарь и т. Д.

Лучшие способы устранения проблем с памятью - этоПрибор утечки, NSZombie и статический анализатор.

5 голосов
/ 22 сентября 2011

Нет, нет общедоступного API для определения того, был ли объект автоматически освобожден.

Даже если бы это было общедоступно, у вашего -retainCountWithAutoRelease метода были бы некоторые проблемы:

  • Объект может быть помещен несколько раз в один и тот же пул автоматического выпуска, поэтому вам потребуется счетчик автоматического выпуска для одного пула автоматического выпуска вместо флага, указывающего, был ли объект автоматически освобожден;

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

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

1 голос
/ 23 сентября 2011

NSAutoreleasePool действительно имеет метод +(void)showPools, о котором я ранее совершенно не знал.Это может быть полезно.Также см. Есть ли способ проверить объекты NSAutoreleasePool? .В этом потоке KennyTM сказал (в комментарии):

Что ж, поскольку содержимое печатается в stderr, вы можете открыть поток и проанализировать его, чтобы получить все указатели

Для справки, я использовал class-dump для платформы Foundation, чтобы увидеть детали NSAutoreleasePool, и у него было следующее:

@interface NSAutoreleasePool : NSObject {
    void *_token;
    void *_reserved3;
    void *_reserved2;
    void *_reserved;
}

+ (void)addObject:(id)arg1;
+ (id)allocWithZone:(struct _NSZone *)arg1;
+ (void)showPools;
+ (void)releaseAllPools;
+ (unsigned int)autoreleasedObjectCount;
+ (unsigned int)topAutoreleasePoolCount;
+ (BOOL)autoreleasePoolExists;
+ (void)enableRelease:(BOOL)arg1;
+ (void)enableFreedObjectCheck:(BOOL)arg1;
+ (unsigned int)poolCountHighWaterMark;
+ (void)setPoolCountHighWaterMark:(unsigned int)arg1;
+ (unsigned int)poolCountHighWaterResolution;
+ (void)setPoolCountHighWaterResolution:(unsigned int)arg1;
+ (unsigned int)totalAutoreleasedObjects;
+ (void)resetTotalAutoreleasedObjects;
- (id)init;
- (void)drain;
- (oneway void)release;
- (id)initWithCapacity:(unsigned int)arg1;
- (void)addObject:(id)arg1;
- (id)retain;
- (unsigned int)retainCount;
- (id)autorelease;
- (void)dealloc;
@end

Я добавил это как ответ, так как это выглядело болееответь более подробно на вопрос, который я задал.

0 голосов
/ 22 сентября 2011

Похоже, вам нужно переопределить метод -(id)autorelease;, поскольку работа по добавлению объекта в NSAutoreleasePool завершена.
Что-то вроде этого:

-(id)autorelease{
    _isAutoreleased = YES;  //some BOOL member initialized to NO and returned on -(BOOL)isAutoreleased;
    [NSAutoreleasePool  addObject:self];
    return self;
}

Также взгляните на эту ссылку

...