Поиск причины EXC_BAD_ACCESS

У меня есть класс со следующим методом инициализации:

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
        StateStack* s = [[StateStack alloc] init];
        state = s;
        [s push:NONE]; //<--EXC_BAD_ACCESS on load here
        [s release];
    }

    return self;
}

И StateStack имеет следующий код инициализации:

- (id)init {
    self = [super init];
    if (self) {
        NSMutableArray* s = [[NSMutableArray alloc] init];
        stack = s;
        [s release];
        NSLog(@"%d",[stack retainCount]);
    }
    return self;
}

Как ни странно, если я удалю строку NSLog, EXC_BAD_ACCESS перейдет к методу Dealloc StateStack:

- (void)dealloc {
    [stack release]; //<--EXC_BAD_ACCESS
    [super dealloc];
}

Поиск вокруг, кажется, предполагает, что EXC_BAD_ACCESS вызван чрезмерным выпуском, но я не вижу, как я что-то перевыпускал. Кто-нибудь знает, в чем может быть причина?


person ario    schedule 25.07.2011    source источник


Ответы (3)


В вашей функции init:

    StateStack* s = [[StateStack alloc] init];
    state = s;
    [s push:NONE]; //<--EXC_BAD_ACCESS on load here
    [s release];

вы выделяете экземпляр StateStack; это получает счетчик удержания, равный 1. Затем в конце функции, которую вы вызываете release, счетчик удержания становится равным 0, и объект готов к освобождению. Таким образом, когда позже выполняется dealloc, state ivar отправляет другой release, и это вызывает плохой доступ. Вам не нужно освобождать s, так как вы хотите сохранить это состояние. Тот же шаблон ошибки возникает в другом методе инициализации.

Это было бы правильно:

- (id)init
{
  self = [super init];
  if (self) {
    // Initialization code here.
    StateStack* s = [[StateStack alloc] init];
    state = s;
    [s push:NONE]; //<--EXC_BAD_ACCESS on load here
  }

  return self;
}

- (id)init {
   self = [super init];
   if (self) {
     NSMutableArray* s = [[NSMutableArray alloc] init];
     stack = s;
   }
   return self;
 }

NB: Я не хочу создавать недоразумения. Использование счетчика сохранения для проверки правильности распределения памяти бесполезно. Это правда. В любом случае, рассуждения с точки зрения количества сохранений помогают понять, что происходит, когда вы выделяете/освобождаете/автоосвобождаете объект. Это базовый механизм, но слишком сложно отследить его использование, чтобы проверить правильность управления памятью.

person sergio    schedule 25.07.2011

state = s не копирует объект NSMutableArray, а просто копирует указатель на него. Поэтому, когда вы вызываете [s release], объект, на который ссылаются как s, так и состояние, освобождается. С этого момента вы будете получать EXC_BAD_ACCESS всякий раз, когда будете использовать любой из них.

Кроме того, не используйте [object retainCount] для отладки проблем с управлением памятью. Это ложь. Гуглите НСЗомби.

person Chris Devereux    schedule 25.07.2011

- (id)init{
self = [super init];
if (self) {
    // Initialization code here.
    state = [[StateStack alloc] init];
    [state push:NONE];
}
return self;
}

Стек состояний

- (id)init {
self = [super init];
if (self) {
    stack = [[NSMutableArray alloc] init];
}
return self;

}

person Anh Pham    schedule 25.07.2011