Зачем мне нужен этот автоматический выпуск после [массива NSMutableArray], чтобы избежать утечки памяти? - PullRequest
1 голос
/ 03 июня 2011

Зачем мне нужно это автоматическое освобождение после [массива NSMutableArray], чтобы избежать утечки памяти?

То есть инструменты сообщили мне, что произошла утечка.Помещение в него авто-релиза решило эту проблему, однако я не уверен, зачем это нужно.Метод «массива» не был похож на INIT или COPY и т. Д. ...

@interface Weekend : NSObject {
    NSMutableArray*     _events;     
}
@property (nonatomic, retain) NSMutableArray* events;
@end

@implementation Weekend

@synthesize events = _events;

- (id)init {
    if (self == [super init])
    {
        self.events = [[NSMutableArray array] autorelease];    // WHY IS THIS AUTORELEASE REQUIRED
    }
    return self;
}

- (void) dealloc {
    [_events release];  _events = nil;
    [super dealloc];
}

@end

ПРИМЕЧАНИЕ. Это то, что я вижу в Intruments, когда я вынимаю аутрелиз (а послеизменил "if (self == [super init])" на "if ((self = [super init]))"

#  Category     Event        Code Location
0  __NSArrayM   Malloc       at the [NSMutableArray array] point
1  __NSArrayM   Autorelease  at the [NSMutableArray array] point
2  __NSArrayM   Retain       at the @synthesize events = _events; point of the code
3  __NSArrayM   Release      QuartzCore - CA:Transaction::observer_callback(__CF........)
                             (from main.m:14 - "int retVal = UIApplicationMain(argc, argv, nil, nil);")

Ответы [ 3 ]

5 голосов
/ 03 июня 2011

Зачем вам нужен этот дополнительный релиз? Вы не Во всяком случае, не там.

Проблема в том, что вы удерживаете _events в другом месте. Может быть, вы передаете его другому классу, который хранится без выпуска? Утечки всегда объясняются инструментами созданием объекта, а не несбалансированным удержанием.

Добавление этого автоматического выпуска вместо обнаружения несбалансированного удержания эквивалентно управлению памятью, когда ответ отключен на 0,3, а просто добавляется 0,3, чтобы исправить это. Вы должны удалить это и исправить реальную проблему.

Edit: после прочтения вашего последнего редактирования, я думаю, вы, вероятно, обнаружите, что Weekend сам просачивается.

2 голосов
/ 03 июня 2011

Эта строка неверна:

self.events = [[NSMutableArray array] autorelease];

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

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

Вот что происходит:

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

Другое дело, что функция массива будет возвращать автоматически выпущенную версию по соглашению.

Функция + (NSArray *)array выглядит примерно так:

+ (NSArray *) array {
   NSArray *ret = [[NSArray alloc] init];
   return [ret autorelease];
}

Ваше свойствотакже имеет флаг "retain", поэтому синтезированные методы выглядят примерно так:

- (NSArray *)events
{
    return [[_events retain] autorelease]; 
}
- (void)setEvents:(NSArray *)anEvents
{
    if (_events != anEvents) {
        [_events autorelease];
        _events = [anEvents retain];
    }
}

Установщик здесь сохранит переданный массив.

Проблема в том, что выавтоматически освобождают объект, который уже был автоматически освобожден, а затем сохранен только еще 1 раз.У вас есть бальзамирование.

По существу, сохранение отсчета началось с 1 (как и все объекты, когда они выделяются), было запланировано для автоматического освобождения в два раза (что будет вычитать два удержания, когда пул сбрасывается в некоторыйточка в будущем), и она сохраняется один раз сеттером.К концу счет сохранения обнулится, и объект будет освобожден, когда вы этого не ожидаете.

в основном:

  1. [NSMutableArray array] ... счетчик сохранения массива равен 1, авторелизы поставлены в очередь для вычитания 1
  2. [array autorelease] ... счетчик хранения массива равенвсе еще 1, но теперь 2 авто-релиза поставлены в очередь, так что вычитайте 2
  3. [self setEvents:...] ... массив сохраняется еще 1 раз, так что теперь счетчик равен 2, очередь автоматического выпуска все еще имеет его в очереди, чтобы вычесть 2 ...
  4. (некоторое время спустя, когда вызывается [NSAutoreleasePool drain/release], обычно с помощью насоса цикла событий) .. массивы освобождаются дважды, потому что ранее они были поставлены в очередь для автоматического выпуска дважды ... сохранить число равно 0. массив свободен.

Теперь что-то может сохранить ваш массив где-то в другом месте, поэтому он и остается.

0 голосов
/ 03 июня 2011

Для начала измените if (self == [super init]) на if (self = [super init])

Затем сначала запустите статический анализатор, исправьте проблемы, а затем перейдите к поиску утечек с помощью инструментов.В любом случае, я почти уверен, что утечка исчезнет, ​​когда вы исправите ошибку (self == ...).

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

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

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

Уточнение:

if (self == [super init]) // End result is YES, execution goes inside of the block but **==** DOES NOT ASSIGN [super init] object to self, single **=** DOES. See the difference? == vs =?
{
    self.myArray = [NSMutableArray array]; // Allocates array on autorelease, assigns it to nil object trough property (code below) which increases retain count, even though self == nil;
}

return self; // self is nil, dealloc can't decrease retain count on _myArray because once you do self.myArray = [NSMutableArray array]; when self is nil, you get dangling pointer and no object has reference to instance of that array, memory leak being end result.


- (void)setMyArray:(NSMutableArray *)inArray
{
    if (_myArray != inArray) 
    {
        [_myArray release];
        _myArray = [inArray retain];
    }
}

Если изменение на if (self = [super init]) не устранило эту утечку, причина кроется в другом месте.

...