Почему этот код просачивается на инструменты?

#iphone #objective-c #memory-management #memory-leaks #retaincount

#iPhone #objective-c #управление памятью #утечки памяти #сохранить количество

Вопрос:

Я выполняю некоторое профилирование памяти на инструментах, и я чувствую, что у меня есть код, который, похоже, выполняет надлежащее управление памятью. Однако instruments убежден, что у меня происходит утечка, и я не могу понять, как устранить утечку.

В моем случае.h У меня есть.

 
@property (nonatomic, copy) NSString *organizer;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSDate *endTime;
@property (nonatomic, copy) NSString *coverCharge;
@property (nonatomic, copy) NSString *ageLimit;
@property (nonatomic, copy) NSString *dressCode;
@property (nonatomic, copy) NSString *venueName;
@property BOOL attendingFlag;
  

Все они выпущены в dealloc

 
- (void) dealloc {
    [type release];
    [organizer release];
    [startTime release];
    [endTime release];
    [coverCharge release];
    [ageLimit release];
    [dressCode release];
    [venueName release];
    [super dealloc];
}   
  

И в моем заводском классе у меня есть

 
-(Event*) getEvent:rs {
    Event *event = [[Event alloc] init];
    event.objId = [NSNumber numberWithInt:[rs intForColumn:DATABASE_EVENT_ID_FIELD]];
    event.name= [rs stringForColumn:DATABASE_EVENT_NAME_FIELD];
    event.organizer = [rs stringForColumn:DATABASE_EVENT_ORGANIZER_FIELD];
    event.type = [rs stringForColumn:DATABASE_EVENT_TYPE_FIELD];
    event.desc= [rs stringForColumn:DATABASE_EVENT_DESCRIPTION_FIELD];
    event.venueName = [rs stringForColumn:DATABASE_EVENT_VENUE_NAME_FIELD];
    event.coverCharge= [rs stringForColumn:DATABASE_EVENT_COVER_CHARGE_FIELD];
    event.dressCode = [rs stringForColumn:DATABASE_EVENT_DRESS_CODE_FIELD];
    event.ageLimit = [rs stringForColumn:DATABASE_EVENT_AGE_LIMIT_FIELD];
    event.region = [[[Region alloc] initWithIdAndName:[NSNumber numberWithInt:[rs intForColumn:DATABASE_EVENT_REGION_ID_FIELD]] name:[rs stringForColumn:DATABASE_EVENT_REGION_NAME_FIELD]] autorelease];
    event.community = [[[Community alloc] initWithIdAndName:[NSNumber numberWithInt:[rs intForColumn:DATABASE_EVENT_COMMUNITY_ID_FIELD]] name:[rs stringForColumn:DATABASE_EVENT_COMMUNITY_NAME_FIELD]] autorelease];
    event.address = [rs stringForColumn:DATABASE_EVENT_ADDRESS_FIELD];
    event.address2 = [rs stringForColumn:DATABASE_EVENT_ADDRESS2_FIELD];
    event.city = [rs stringForColumn:DATABASE_EVENT_CITY_FIELD];
    event.state = [rs stringForColumn:DATABASE_EVENT_STATE_FIELD];
    event.zip = [rs stringForColumn:DATABASE_EVENT_ZIP_FIELD];
    event.country = [rs stringForColumn:DATABASE_EVENT_COUNTRY_FIELD];
    event.phone = [rs stringForColumn:DATABASE_EVENT_PHONE_FIELD];
    event.webpage = [rs stringForColumn:DATABASE_EVENT_WEBPAGE_FIELD];

    return [event autorelease];
}
  

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

Instruments жалуется на утечку в Event alloc и еще одну в каждой строке в селекторе getEvent. rs — это объект resultset из библиотеки (FMDB), который я использую во всем приложении, и, похоже, это единственный объект, где обнаруживаются эти утечки, поэтому я почти уверен, что проблема не в этом. На самом деле я недавно использовал эту же библиотеку для другого проекта, и из-за нее не было никаких утечек, поэтому я устранил ее как источник утечки.

(a) Я явно автоматически выпускаю объект event при его возврате.

(b) Все мои установщики получают объекты с автоматическим выпуском, поэтому я только увеличиваю количество сохранений, как рекомендовано документами по управлению памятью для objective c.

Есть идеи, почему строка alloc и почти каждая следующая за ней строка могут протекать?

Ответ №1:

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

Все остальные строки помечены как утечки, потому что происходит утечка объекта Event.

Что нужно сделать, так это добавить инструмент распределения в дополнение к утечкам и убедиться, что для него установлено значение «записывать количество ссылок» (маленький (i) в строке распределения на графике времени). Затем запустите свое приложение, обратите внимание на утечку. Затем выберите инструмент распределения, выберите «создано и все еще работает» и найдите объекты событий, которые все еще существуют.

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

Комментарии:

1. Спасибо Кендалл. Это имеет смысл. На самом деле я обнаружил другую утечку в клиентском коде, который использовал события, поэтому мне интересно, было ли это причиной. Я никогда не запускал его после этого, потому что думал, что мне нужно что-то исправить в коде, который я опубликовал. Я собираюсь снова запустить instruments, и если события все еще будут протекать, я последую вашему совету и вернусь с результатами. Спасибо за рекомендацию.

2. Привет, Кендалл. Похоже, что мое исправление клиентского кода устранило эту проблему. Тем не менее, вы дали мне несколько очень полезных советов, которые я собираюсь использовать для устранения пары других утечек, которые у меня есть. Я отдаю вам должное за ответ, потому что ваш комментарий о том, что это проблема с клиентским кодом для события, был очень показательным и полезным. 😉