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. Якщо ви приїхали з іншого фону, це може зайняти трохи часу, перш ніж реально втілити правила управління пам’яттю - якщо ви не зробите це в цьому.

Пам'ятайте, що все, що ви отримуєте від функції розподілу (зазвичай це метод статичного алокації, але є кілька інших), або методом копіювання, ви теж володієте пам'яттю і маєте звільнити її, коли закінчите.

Але якщо ви отримаєте щось з майже нічого іншого, включаючи фабричні методи (наприклад [NSString stringWithFormat]), тоді ви матимете посилання на автовипуск, а це означає, що він може бути випущений на якийсь час у майбутньому за допомогою іншого коду - тому дуже важливо, якщо вам це потрібно щоб утримати його поза межами безпосередньої функції, яку ви зберігаєте. Якщо ви цього не зробите, пам'ять може залишатися виділеною під час її використання або бути звільненою, але випадково все ще дійсною, під час тестування емулятора, але, швидше за все, буде звільнена та виявиться як помилка доступу під час роботи на пристрої.

Найкращий спосіб відстежити ці речі, і все-таки хороша ідея (навіть якщо явних проблем немає) - запустити додаток в інструменті «Інструменти», особливо за допомогою параметра «Витоки».


2
У мене був якийсь код відбору проб акселерометра, який не був життєво важливим для мого додатка, який після видалення усунув погану помилку доступу. Що має сенс вважати, що в тренажері немає акселерометра. Мені здається дивним, що цей код існував, недоторканий, за тиждень до того, як викликати цю помилку ...
Гектор Рамос

Я новачок у Objective-C, тому більшість моїх проблем повинні виникати внаслідок управління пам'яттю. Після декількох років роботи на C ++, я використовую переважно Java протягом останніх трьох-чотирьох років, тож я затуманився в управлінні пам’яттю. Дякую за вашу відповідь!
Гектор Рамос

4
Немає проблем - радий, що ви виправили це. Управління пам’яттю насправді не важко досягти найкращого рівня - вам просто потрібно переконатися, що ви засвоїте правила та перейдете на добрі звички.
фільтрований

Моя проблема, здається, полягає виключно в тому, що я занадто агресивно випускаю рядки (і такі), які я створюю. Я все ще не на 100% впевнений у тому, що слід звільнити та коли, але відповідь Філа, безумовно, допомогла.
pluckyglen

Якщо я дотримувався цього правильно, cmculloh, так, це було правильно зробити. Ви не володієте поверненням об'єкта від objectAtIndex.
фільтрований

101

Основна причина EXC_BAD_ACCESS полягає в спробі доступу до звільнених об'єктів.

Щоб дізнатися, як вирішити цю проблему, прочитайте цей документ: DebuggingAutoReleasePool

Навіть якщо ви не думаєте, що "випускаєте автоматично випущені об'єкти", це стосується вас.

Цей метод працює надзвичайно добре. Я використовую його весь час з великим успіхом !!

Підсумовуючи це, це пояснює, як використовувати клас налагодження NSZombie Cocoa та інструмент командного рядка "malloc_history", щоб знайти саме те, до якого випущеного об'єкта було доступно у вашому коді.

Sidenote:

Запуск інструментів і перевірка на наявність витоків не допоможуть усунути неполадки EXC_BAD_ACCESS. Я впевнений, що витоки пам'яті не мають нічого спільного з EXC_BAD_ACCESS. Визначення витоку - це об'єкт, до якого ви більше не маєте доступу, і тому ви не можете його назвати.

ОНОВЛЕННЯ: Зараз я використовую інструменти для налагодження витоків. З Xcode 4.2 виберіть Product-> Profile, а при запуску Instruments виберіть "Zombies".


18
Цей сиденот є дуже важливим. Витоки не можуть спричинити EXC_BAD_ACCESS (у них інші проблеми). Я написав це, щоб спробувати усунути помилки щодо EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Лу Франко,

4
Цей інструмент зомбі в Xcode є геніальним! Я знайшов винуватця за 3 хв не години.
Арам Кочарян

1
вище посилання у відповідь не доступне. Показує помилку 404 не знайдено.
Теяс

12

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

Я не знайомий з розробкою iPhone, але вам слід двічі перевірити всі свої вказівники на буфер, які ви передаєте на системні дзвінки. Повністю підтягніть рівень попередження вашого компілятора (за допомогою gcc, використовуйте параметри -Wallта -Wextra). Увімкніть якомога більше діагностики на тренажері / налагоджувачі.


8

На мій досвід, це, як правило, викликано незаконним доступом до пам'яті. Перевірте всі вказівники, особливо об’єктні покажчики, щоб переконатися, що вони ініціалізовані. Переконайтесь, що файл MainWindow.xib, якщо ви його використовуєте, налаштований належним чином із усіма необхідними підключеннями.

Якщо жодна з цих перевірок на папері нічого не вимикає, і це не відбувається при однократному кроці, спробуйте знайти помилку з операторами NSLog (): посипте їх кодом, переміщуючи їх, поки ви не виділите рядок, що викликає помилка. Потім встановіть точку перерви на цій лінії та запустіть програму. Коли ви потрапили на точку розриву, вивчіть усі змінні та об'єкти в них, щоб побачити, чи щось не виглядає так, як ви очікували. Особливо слідкуйте за змінними, клас об'єктів яких ви не очікували. Якщо змінна повинна містити вікно UIW, але у неї замість цього є NSNotification, та сама основна помилка коду може проявлятися по-іншому, коли налагоджувач не працює.


7

Я щойно провів пару годин, відстежуючи EXC_BAD_ACCESS і виявив, що NSZombies та інші оточення не здавались мені нічого.

Для мене це був дурний вислів NSLog із специфікаторами формату, але жодних аргументів не було.

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

Виправлено

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

6

Відео WWDC 2010 року доступне для всіх учасників програми для розробників яблук. Є чудове відео: "Сесія 311 - розширений аналіз пам'яті за допомогою інструментів", де показано кілька прикладів використання зомбі в інструментах та налагодження інших проблем із пам'яттю.

Для посилання на сторінку входу натисніть ТУТ .


6

Не повна відповідь, але одна конкретна ситуація, коли я отримав це, коли намагаюся отримати доступ до об'єкта, який 'загинув', тому що я намагався використовувати автовипуск:

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"];

виправляє проблему.


Це не викликає для мене жодної помилки, оскільки рядок стає ініціалізованою до нуля, а використання нульового шаблону об'єкта викликає метод на nil нічого не робить.
Лірон Ягдав

5

Інший метод вилучення винятків EXC_BAD_ACCESS до їх виникнення - це статичний аналізатор у XCode 4+.

Запустіть статичний аналізатор за допомогою Product> Analyze (shift + cmd + B). Клацання будь-яких повідомлень, генерованих аналізатором, накладе діаграму на вашому джерелі, що відображає послідовність утримувань / випусків об'єкта-порушника.

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


5

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

Інструкції можна знайти тут DebuggingTechniques


4

Скористайтеся простим правилом "якщо ви не виділили його чи не зберегли його, не звільняйте".


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-метод ...;)


Це має бути попередженням / помилкою часу компіляції, а не EXC_BAD_ACCESS під час виконання.
stigi

3

Це відмінна нитка. Ось мій досвід: я переплутався з ключовим словом зберегти / призначити в декларації властивості. Я сказав:

@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;

1
Дивно, навіщо вам потрібно зберігати IBOutlet? Їх управління здійснюється для вас автоматично.
jv42

3

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

EXC_BAD_ACCESS стався одразу після точки введення методу, і я досить довго плутався через те, що він ніде не був декларацією масиву.

Можливо, хтось ще може отримати користь від моїх кількох годин зачісування волосся.


3

Забули взяти з нього нелот-вказівник dealloc . Я отримував exc_bad_access у своєму rootView UINavigationController, але лише іноді. Я припускав, що проблема була в rootView, оскільки вона вибилася на півдорозі через viewDidAppear {}. Це виявилося лише після того, як я вискочив погляд із поганим звільненням {}, і це було все!

"EXC_BAD_ACCESS" [Перехід на процес 330] Зараз не доступна пам'ять для програмування: небезпечний для виклику malloc

Я думав, що це проблема, коли я намагаюся виділити ... не там, де я намагався звільнити нелот, D'oh!


3

Як я маю справу з EXC_BAD_ACCESS

Іноді я відчуваю, що коли буде видалено помилку EXC_BAD_ACCESS, xcode покаже помилку в класі main.m, не даючи додаткової інформації про те, де відбувається збій (Іноді).

У ті часи ми можемо встановити Виняткову точку розриву в Xcode, так що коли виняток буде спіймано, то точка розриву буде розміщена і безпосередньо інтимуватиме користувача, що в цьому рядку стався збій.

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


2

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


2

У мене просто була ця проблема. Для мене причиною було видалення керованого об’єктом CoreData та спробу прочитати його з іншого місця.


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
Абсолютно не потрібно виділяти та ініціалізувати змінну, якщо ви негайно збираєтеся її замінити іншою. Ви просто просочили об’єкт у першому завданні.
dreamlax

2

Просто додати

Lynda.com є фантастичний DVD під назвою

Основне навчання iPhone SDK

і Глава 6, Урок 3 - це все EXEC_BAD_ACCESS та роботу із Zombies.

Мені було чудово зрозуміти, не тільки код помилки, але як я можу використовувати зомбі, щоб отримати більше інформації про звільнений об’єкт.


2

Щоб перевірити, яка може бути помилка

Використовуйте NSZombieEnabled.

Щоб активувати об’єкт NSZombieEnabled у вашій програмі:

Виберіть Project> Edit Active Executable, щоб відкрити вікно інформації, яке виконується. Клацніть Аргументи. Клацніть на кнопці додати (+) у розділі «Змінні, які потрібно встановити в середовищі». Введіть NSZombieEnabled у стовпець Ім'я та ТАК у стовпці Значення. Переконайтесь, що вибрано галочку для запису NSZombieEnabled.

Я знайшов цю відповідь на iPhoneSDK


2

Я усвідомлюю, що це було запитано деякий час тому, але прочитавши цю тему, я знайшов рішення для XCode 4.2: Продукт -> Редагувати схему -> Вкладка діагностики -> Увімкнути об'єкти зомбі

Допоміг мені знайти повідомлення, яке надсилається до розміщеного об’єкта.


2

Коли у вас є нескінченна рекурсія, я думаю, ви також можете мати цю помилку. Це був для мене випадок.


1

Ще одна можливість: використовуючи блоки в черзі, може легко статися, що ви намагаєтеся отримати доступ до об’єкта в іншій черзі, що вже було відведено на цей час. Як правило, коли ви намагаєтесь щось надіслати до GUI. Якщо ваша точка виключення встановлена ​​в чужому місці, то це може бути причиною.


1

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


1

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

Використовуй це:

@"Some String"

Замість цього:

"Some String"

PS - зазвичай під час заповнення вмісту arrayз великою кількістю записів.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.