Управление памятью в Objective-C - PullRequest
2 голосов
/ 07 января 2010
#import <Foundation/Foundation.h>

int main (int argc, char const *argv[])
{
    SampClass *obj=[[SampClass alloc] init];
    [obj release];
    NSLog(@"%i", [obj retainCount]);
    return 0;
}

Почему это дает retainCount 1, когда оно должно быть 0

Ответы [ 4 ]

9 голосов
/ 07 января 2010

Не звоните retainCount.

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

Абсолютный счет объекта не находится под вашим контролем. Часто значение будет довольно неожиданным. Может быть любое количество кэшей, статических распределений (например, констант NSStrings) или других внутренних деталей реализации в рамках, которые делают количество сохраняемых объектов отличным от ожидаемого.

Сохраняемое количество объектов следует рассматривать исключительно в терминах дельт. Если вы заставляете счет удерживать увеличиваться, вы должны уменьшить его где-нибудь, если хотите, чтобы объект был освобожден. Период. Конец истории.

Попытка представить счет в абсолютном выражении просто приведет к путанице и потерянным часам.

Руководство по управлению памятью какао объясняет это довольно хорошо.

1 голос
/ 07 января 2010

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

heimdall:~ leeg$ pbpaste | sed s/SampClass/NSObject/g > fubar.m
heimdall:~ leeg$ cc -o fubar -framework Foundation fubar.m 
heimdall:~ leeg$ NSZombieEnabled=YES ./fubar
2010-01-07 13:40:10.477 fubar[871:903] *** -[NSObject retainCount]: message sent to deallocated instance 0x10010d8f0
Trace/BPT trap
0 голосов
/ 07 января 2010

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

Если вы скомпилируете и запустите 32-битную версию, вы получите сообщение об ошибке ( сообщение retainCount отправлено освобожденному объекту = 0x ... ).

Я предполагаю, что 64-битная среда выполнения (опция компиляции по умолчанию на Leopard) не собирает объекты так агрессивно, как 32-битная среда выполнения, поэтому ваш вызов retainCount не вызывает ошибку.

Чтобы проверить, действительно ли ваш объект освобожден, используйте dealloc для вашего SampClass:

- (void) dealloc
{
    NSLog(@"Dealloc");
    [super dealloc];
}

Позднее редактирование : Как я и подозревал, разница в поведении между 32 и 64 битами при вызове метода для освобожденного объекта связана с временем выполнения, а не с неопределенным поведением.

В 32-битном виде после освобождения класса указатель isa переключается на специальный класс, позволяющий перехватывать сообщения для освобожденных объектов. Это не происходит в 64 бит. Соответствующий источник: objc-class.m :

#if !__OBJC2__ 
    // only clobber isa for non-gc
    anObject->isa = _objc_getFreedObjectClass (); 
#endif
0 голосов
/ 07 января 2010

Поскольку объект был освобожден до вызова NSLog.

Я предполагаю, что релиз реализован примерно так:

if(retainCount==1) [self dealloc];
else retainCount--;

и вы незаконно получаете доступ к освобожденному объекту.

Обновление: Нашли эти вопросы, ответы на которые должны вас просветить: здесь и здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...