Получен сигнал EXC_BAD_ACCESS

290

При развертывании приложения на устройстве программа закроется через несколько циклов со следующей ошибкой:

Program received signal: "EXC_BAD_ACCESS".

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

В данном конкретном случае произошла ошибка в коде акселерометра. Он не будет выполняться в симуляторе, поэтому не выдает никаких ошибок. Тем не менее, он будет выполняться после развертывания на устройстве.

Большинство ответов на этот вопрос имеют дело с общей EXC_BAD_ACCESSошибкой, поэтому я оставлю это открытым как универсальное средство для страшной ошибки Bad Access.

EXC_BAD_ACCESSобычно выбрасывается в результате несанкционированного доступа к памяти. Вы можете найти больше информации в ответах ниже.

Вы сталкивались с EXC_BAD_ACCESSсигналом раньше, и как вы с ним справились?

Эктор Рамос
источник

Ответы:

196

Из вашего описания я подозреваю, что наиболее вероятным объяснением является то, что у вас есть какая-то ошибка в управлении вашей памятью. Вы сказали, что работали над разработкой для iPhone в течение нескольких недель, но не знаете, имеете ли вы опыт работы с Objective C в целом. Если вы пришли из другой среды, может потребоваться некоторое время, прежде чем вы действительно усвоите правила управления памятью - если вы не сделаете этого.

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

Но если вы получите что-то от чего-то еще, включая фабричные методы (например [NSString stringWithFormat]), то у вас будет ссылка для автоматического выпуска, что означает, что она может быть освобождена в будущем другим кодом - поэтому очень важно, чтобы, если вам нужно держать его за пределами непосредственной функции, которую вы сохраните. Если вы этого не сделаете, память может остаться выделенной во время ее использования или быть освобожденной, но, по совпадению, все еще действующей, во время тестирования вашего эмулятора, но с большей вероятностью будет освобождена и будет отображаться как ошибка неверного доступа при работе на устройстве.

Лучший способ отследить эти вещи, и хорошая идея в любом случае (даже если нет явных проблем) - запустить приложение в инструменте инструментов, особенно с опцией «Утечки».

philsquared
источник
2
У меня был некоторый код выборки акселерометра, который не был жизненно важен для моего приложения, который после удаления устранял ошибку неверного доступа. Что имеет смысл, учитывая, что на симуляторе нет акселерометра. Я нахожу странным, что этот код существовал без изменений в течение недели, прежде чем вызвать эту ошибку ...
Гектор Рамос
Я новичок в Objective-C, поэтому большинство моих проблем должно быть связано с управлением памятью. После нескольких лет работы в C ++ я в течение последних трех или четырех лет использовал в основном Java, так что я не справился с управлением памятью. Спасибо за Ваш ответ!
Гектор Рамос
4
Нет проблем - рад, что вы это исправили. Управлять памятью не так уж сложно, нужно просто убедиться, что вы выучили правила и приобрели хорошие привычки.
philsquared
Кажется, проблема в том, что я слишком агрессивен в выпуске струн (и подобных), которые я создаю. Я все еще не уверен на 100%, что и когда должно быть выпущено, но ответ Фила определенно помог.
pluckyglen
Если бы я следовал этому правильно, cmculloh, да, это было правильно. Вы не являетесь владельцем возврата объекта из objectAtIndex.
philsquared
101

Основной причиной EXC_BAD_ACCESS является попытка доступа к освобожденным объектам.

Чтобы узнать, как решить эту проблему, прочитайте этот документ: DebuggingAutoReleasePool

Даже если вы не думаете, что «выпускаете автоматически выпущенные объекты», это относится к вам.

Этот метод работает очень хорошо. Я использую его все время с большим успехом!

Таким образом, это объясняет, как использовать класс отладки NSZombie и инструмент командной строки «malloc_history», чтобы точно узнать, к какому освобожденному объекту был получен доступ в вашем коде.

Примечание:

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

ОБНОВЛЕНИЕ: теперь я использую инструменты для устранения утечек. В Xcode 4.2 выберите Product-> Profile, а после запуска Instruments выберите «Zombies».

bentford
источник
18
Этот знак очень важен. Утечки не могут вызвать EXC_BAD_ACCESS (у них есть другие проблемы). Я написал это, чтобы попытаться прояснить неправильные представления о EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Лу Франко,
4
Этот инструмент зомби в Xcode великолепен! Я нашел виновника в 3 минуты, а не в часах.
Арам Кочарян
1
Выше ссылка в ответе недоступна. Показывает 404 не найдена ошибка.
Tejas
12

Сигнал EXC_BAD_ACCESS является результатом передачи неверного указателя на системный вызов. Сегодня я получил его с тестовой программой для OS X - я передавал неинициализированную переменную pthread_join(), что было связано с более ранней опечаткой.

Я не знаком с разработкой для iPhone, но вы должны дважды проверить все ваши указатели буфера, которые вы передаете системным вызовам. Crank до уровня предупреждения вашего компилятора всего путь (с GCC, используйте -Wallи -Wextraопцию). Включите как можно больше диагностики на симуляторе / отладчике.

Адам Розенфилд
источник
8

По моему опыту, это обычно вызвано незаконным доступом к памяти. Проверьте все указатели, особенно указатели объектов, чтобы убедиться, что они инициализированы. Убедитесь, что ваш файл MainWindow.xib, если вы его используете, настроен правильно, со всеми необходимыми соединениями.

Если ни одна из этих проверок на бумаге ничего не приводит к успеху, а при пошаговом выполнении ничего не происходит, попробуйте найти ошибку с помощью операторов NSLog (): посыпьте их кодом, перемещая их, пока не изолируете строку, которая вызывает Ошибка. Затем установите точку останова на этой строке и запустите вашу программу. Когда вы дойдете до точки останова, изучите все переменные и объекты в них, чтобы увидеть, не выглядит ли что-нибудь не так, как вы ожидаете. Я бы особенно следил за переменными, чей класс объектов - это то, чего вы не ожидали. Если переменная должна содержать UIWindow, но вместо этого она содержит NSNotification, та же самая ошибка основного кода может проявляться по-другому, когда отладчик не работает.

Брент Роял-Гордон
источник
7

Я просто потратил пару часов на отслеживание EXC_BAD_ACCESS и обнаружил, что NSZombies и другие env-переменные, похоже, ничего мне не говорили.

Для меня это был глупый оператор NSLog с указателями формата, но без аргументов.

NSLog(@"Some silly log message %@-%@");

Исправлено

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);
Скотт Хиберлин
источник
6

Видео 2010 WWDC доступны для всех участников программы для разработчиков Apple. Есть отличное видео: «Сессия 311 - Расширенный анализ памяти с помощью инструментов», в котором показаны некоторые примеры использования зомби в инструментах и ​​устранения других проблем с памятью.

Для ссылки на страницу входа нажмите ЗДЕСЬ .

Иона
источник
6

Не полный ответ, но одна конкретная ситуация, в которой я получил это, когда пытаюсь получить доступ к объекту, который «умер», потому что я пытался использовать autorelease:

netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];

Так, например, я фактически передавал это как объект для «уведомления» (зарегистрировал его как слушателя, наблюдателя, независимо от того, что вам нравится), но он уже умер после отправки уведомления, и я получил EXC_BAD_ACCESS. Изменение этого значения [[MyNetObject alloc] init]и его последующее освобождение исправили ошибку.

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

myObjectDefinedInHeader = aParameterObjectPassedIn;

Позже при попытке доступа к myObjectDefinedInHeader у вас могут возникнуть проблемы. С помощью:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

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

обкрадывать
источник
5

Просто чтобы добавить еще одну ситуацию, где это может произойти:

У меня был код:

NSMutableString *string;
[string   appendWithFormat:@"foo"];

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

NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

устраняет проблему

gnuchu
источник
Это не вызывает у меня никакой ошибки, потому что строка инициализируется значением nil, и использование шаблона нулевого объекта, вызывающего метод для nil, ничего не делает.
Лирон Яхдав
5

Еще один метод отлова исключений EXC_BAD_ACCESS до их возникновения - это статический анализатор в XCode 4+.

Запустите статический анализатор, выбрав Product> Analyze (shift + cmd + B). При нажатии на любые сообщения, сгенерированные анализатором, будет наложена диаграмма на ваш источник, показывающая последовательность удержаний / выпусков объекта, нарушившего работу.

введите описание изображения здесь

ericsoco
источник
5

Я считаю полезным установить точку останова на objc_exception_throw. Таким образом, отладчик должен сломаться, когда вы получите EXC_BAD_ACCESS.

Инструкции можно найти здесь DebuggingTechniques

lyonanderson
источник
4

Используйте простое правило «если вы его не распределили или не сохранили, не выпускайте его».

Гамма-Point
источник
1
Расширьте это правило словами "... скопируйте его ...", и все будет в порядке.
до
4

Как отлаживать EXC_BAD_ACCESS

Проверьте ссылку выше и сделайте, как говорится .... Просто несколько быстрых инструкций по использованию NSZombies

Запустите приложение и после его сбоя (должно отображаться «Прервано», а не «EXC_BAD_ACCESS» ... проверьте консоль («Выполнить»> «Консоль») ... там должно появиться сообщение, сообщающее, к какому объекту оно пыталось получить доступ).

-Бен

Бен Колл
источник
3

Я отлаживал и рефакторинг кода для решения этой ошибки в течение последних четырех часов. Пост выше привел меня, чтобы увидеть проблему:

Свойство перед: startPoint = [[DataPoint alloc] init]; startPoint = [DataPointList objectAtIndex: 0];
, , , x = startPoint.x - 10; // EXC_BAD_ACCESS

Свойство после: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] сохранить];

До свидания EXC_BAD_ACCESS


источник
Я сделал аналогичную ошибку. Я забыл восстановить экземпляр, который вызвал аварию, и потратил часы, чтобы понять это. Твой опыт зажег меня, чтобы узнать мой. Спасибо!
David.Chu.ca
3

Надеюсь, что вы отпустите «строку», когда вы закончите!


источник
3

Я забыл вернуть себя в init-метод ...;)

denbec
источник
Это должно быть предупреждение / ошибка времени компиляции, а не EXC_BAD_ACCESS во время выполнения.
Стиги
3

Это отличная тема. Вот мой опыт: я перепутал ключевое слово retain / assign в объявлении свойства. Я сказал:

@property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;

где я должен был сказать

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
fool4jesus
источник
1
Странно, зачем вам сохранять IBOutlet? Их управление сделано для вас автоматически.
jv42
3

Я столкнулся с EXC_BAD_ACCESS на iPhone только при попытке выполнить метод C, который включал большой массив. Симулятор смог дать мне достаточно памяти для запуска кода, но не устройства (массив был миллион символов, так что это было слишком много!).

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

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

mblackwell8
источник
3

Забыл вытащить неиспользуемый указатель dealloc. Я получал exc_bad_access на моем rootView UINavigationController, но только иногда. Я предположил, что проблема была в rootView, потому что он зависал в середине своего viewDidAppear {}. Это случилось только после того, как я опубликовал представление с выпуском bad dealloc {}, и все!

«EXC_BAD_ACCESS» [Переключение на процесс 330] Нет доступной памяти для программирования сейчас: небезопасно вызывать malloc

Я думал, что это была проблема, когда я пытался выделить ... не там, где я пытался выпустить нераспределенный, D'Oh!

мистифицировать
источник
3

Как я справляюсь с EXC_BAD_ACCESS

Иногда я чувствую, что когда выдается ошибка EXC_BAD_ACCESS, xcode покажет ошибку в классе main.m, не предоставляя дополнительной информации о том, где происходит сбой (иногда).

В те времена мы можем установить Исключительную точку останова в XCode так, чтобы, когда исключение было поймано, точка останова была помещена и непосредственно проинформировала бы пользователя о сбое в этой строке.

введите описание изображения здесь

iPrabu
источник
2

Вызов NSAssert () для проверки параметров метода очень удобен для отслеживания и предотвращения передачи нулей.

Райан Тауншенд
источник
2

У меня просто была эта проблема. Для меня причиной было удаление управляемого объекта CoreData и попытка прочитать его потом из другого места.

konryd
источник
2

Я отлаживал и рефакторинг кода для решения этой ошибки в течение последних четырех часов. Пост выше привел меня, чтобы увидеть проблему:

Недвижимость до:

startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS

Недвижимость после:

startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];

Прощай EXC_BAD_ACCESS

Большое спасибо за ваш ответ. Я боролся с этой проблемой весь день. Ты восхитителен!


источник
4
Разве вы не просто сразу перезаписали startPoint? Я не думаю, что вам нужна эта первая строка вообще.
Toxaq
2
Абсолютно нет необходимости выделять и инициализировать переменную, если вы собираетесь немедленно перезаписать ее другой. Вы просто слили объект в первом задании.
сонлакс
2

Просто добавить

Lynda.com имеет фантастический DVD под названием

iPhone SDK Essential Training

и глава 6, урок 3, посвящена EXEC_BAD_ACCESS и работе с зомби.

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

balexandre
источник
2

Чтобы проверить, в чем может быть ошибка

Используйте NSZombieEnabled.

Чтобы активировать функцию NSZombieEnabled в вашем приложении:

Выберите «Проект»> «Редактировать активный исполняемый файл», чтобы открыть окно информации о исполняемом файле. Нажмите Аргументы. Нажмите кнопку добавления (+) в разделе «Переменные, которые должны быть установлены в среде». Введите NSZombieEnabled в столбце Имя и YES в столбце Значение. Убедитесь, что установлен флажок для записи NSZombieEnabled.

Я нашел этот ответ на iPhoneSDK

zambono
источник
2

Я понимаю, что это было задано некоторое время назад, но после прочтения этой темы я нашел решение для XCode 4.2: Продукт -> Редактировать схему -> Вкладка Диагностика -> Включить объекты-зомби

Помог мне найти сообщение, отправляемое на освобожденный объект.

Шон Айткен
источник
2

Когда у вас бесконечная рекурсия, я думаю, что вы также можете иметь эту ошибку. Это был случай для меня.

coolcool1994
источник
1

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

brainray
источник
1

Я получил это, потому что я не использовал [self performSegueWithIdentifier:sender:]и -(void) prepareForSegue:(UIstoryboardSegue *)правильно

DHShah01
источник
1

Не забывайте @символ при создании строк, рассматривая C-stringsкак NSStringsбудет причиной EXC_BAD_ACCESS.

Использовать это:

@"Some String"

Вместо этого:

"Some String"

PS - обычно при заполнении содержимого arrayмножеством записей.

Артур
источник