Два вопроса управления памятью Objective-C: всегда ли обнаружение утечек верно?и почему авто-релиз работает, но не выпускает? - PullRequest
3 голосов
/ 24 декабря 2010

Я только что обнаружил следующее: Как я и ожидал, при освобождении моего объекта перед его возвратом происходит сбой приложения:

   + (NSString *)descriptionOfExpression:(NSArray *)anExpression {
    NSMutableString *expressionDescription;
    expressionDescription = [[NSMutableString alloc] init];  
    for (id object in anExpression) {
    //Do stuff to expressionDescription
    }

    [expressionDescription release];
    return expressionDescription;
}

Однако я не ожидал, что следующее вызовет утечку памяти:

    + (NSString *)descriptionOfExpression:(NSArray *)anExpression {
    NSMutableString *expressionDescription;
    expressionDescription = [[NSMutableString alloc] init];  
    for (id object in anExpression) {
    //Do stuff to expressionDescription
    }

    return expressionDescription;
    [expressionDescription release];
}

В конечном итоге мое решение заключалось в том, чтобы сделать это вместо:

    + (NSString *)descriptionOfExpression:(NSArray *)anExpression {
    NSMutableString *expressionDescription;
    expressionDescription = [[NSMutableString alloc] init];  
    for (id object in anExpression) {
    //Do stuff to expressionDescription
    }

    [expressionDescription autorelease];
    return expressionDescription;
}

Я понимаю, почему это работает с автоматическим выпуском, но как возникает утечка, вызванная освобождением после возврата значения?

Мой второй вопрос очень связан: всегда ли правильны системы обнаружения утечек памяти?

Я понимаю, что программисты, которые разработали Instruments и функцию сборки и анализа в XCode, гораздо более опытны в этом вопросе, чем я, поэтому сейчас я предполагаю, что они всегда правы.Однако мне трудно понять, как такая программа, как «Инструменты», может «узнать», что память просочилась.Я думаю, это должно полностью зависеть от того, как долго я, программист, хочу использовать объект.

Это мое понимание того, что такое «утечка»:

Определение человека: Память протекает, если у меня выделена память, когда я ее не использую.

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

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

Ответы [ 3 ]

5 голосов
/ 24 декабря 2010

Проблема с вашим вторым блоком в том, что после возврата код не запускается.Я бы ожидал, что XCode предупредит вас об этом (посмотрите и попытайтесь исправить ваши предупреждения, а также ошибки)

Ваше понимание утечек верно.Построить и проанализировать можно обмануть - он опирается на соблюдение правил кодирования.Если вы отклонитесь от этого, B & A не узнает (или отметит утечки, которые не соответствуют действительности).

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

Когда вы возвращаете объектчто вы выделяете, выполните одно из следующих действий:

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

  2. Назовите ваше сообщение allocSOMETHING или newSOMETHING и не вызывайте autorelease.В этом случае под вашим сообщением понимается возвращение объекта с сохраненным счетчиком, равным единице, и вызывающий отвечает за его освобождение (или автоматическое освобождение).

Если вы выполните одно из следующих действий:эти вещи, Build and Analyze поймет и поможет вам сделать все правильно.

РЕДАКТИРОВАТЬ: добавлено newSOMETHING на основе комментария

2 голосов
/ 24 декабря 2010

Для первой части вашего вопроса ответ основан на том, когда autorelease фактически освобождает объект.

  • Первый пример освобождает объект, прежде чем он будет возвращен и использован.Вы получаете сбой, потому что память больше не существует.
  • Второй пример никогда не освобождает память, возвращение приводит к тому, что управление покидает метод.Таким образом, ваш вызов освобождения находится в «ничейной стране» кода, он никогда не выполняется.
  • Ваш последний пример работает, потому что autorelease добавляет объект в список объектов, которые будут освобождены (так называемый пул autorelease).Когда пул очищается, всем объектам в нем отправляется сообщение об освобождении.Стандартный пул очищается, когда цикл событий прерывается, по существу, после того, как ваши методы вернули управление в ОС.Из-за этого он есть, пока вы хотите его использовать, но в долгосрочной перспективе он автоматически удаляется.

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

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

1 голос
/ 24 декабря 2010

Всегда ли правильны системы обнаружения утечек памяти?

Нет.Я дал аналогичный ответ на другой вопрос: инструмент Leaks очень консервативен.Все, что он сообщает как утечка, действительно является утечкой, но не обязательно сообщает обо всех утечках.Статический анализатор опирается на знание правил работы API-интерфейсов Cocoa / Cocoa Touch, поэтому он не всегда может сделать это правильно.Например, он не знает, что -[NSTimer invalidate] освобождает получателя, потому что это не является частью общих соглашений API.

Инструмент Zombies (вы не можете, AFAICT, использовать его с приложениями iOS) надругая рука логически идеальна: любая попытка получить доступ к объекту зомби была бы замечена (это идентифицировало бы проблему, о которой вы говорили выше).Однако он обладает большой дозой эффекта наблюдателя.

...