Sinyal EXC_BAD_ACCESS diterima

290

Saat menyebarkan aplikasi ke perangkat, program akan berhenti setelah beberapa siklus dengan kesalahan berikut:

Program received signal: "EXC_BAD_ACCESS".

Program ini berjalan tanpa masalah pada simulator iPhone, itu juga akan debug dan berjalan selama saya melangkah melalui instruksi satu per satu. Begitu saya membiarkannya berjalan lagi, saya akan menekan EXC_BAD_ACCESSsinyalnya.

Dalam kasus khusus ini, itu terjadi kesalahan dalam kode akselerometer. Itu tidak akan dieksekusi di dalam simulator, itu sebabnya ia tidak melakukan kesalahan. Namun, itu akan dieksekusi setelah dikerahkan ke perangkat.

Sebagian besar jawaban untuk pertanyaan ini berhubungan dengan EXC_BAD_ACCESSkesalahan umum , jadi saya akan membiarkan ini terbuka sebagai jawaban untuk semua kesalahan Akses Buruk yang ditakuti.

EXC_BAD_ACCESSbiasanya dilemparkan sebagai akibat dari akses memori ilegal. Anda dapat menemukan informasi lebih lanjut dalam jawaban di bawah ini.

Pernahkah Anda menemukan EXC_BAD_ACCESSsinyal sebelumnya, dan bagaimana Anda menghadapinya?

Héctor Ramos
sumber

Jawaban:

196

Dari uraian Anda, saya menduga penjelasan yang paling mungkin adalah bahwa Anda memiliki beberapa kesalahan dalam manajemen memori Anda. Anda bilang Anda telah bekerja pada pengembangan iPhone selama beberapa minggu, tetapi tidak apakah Anda berpengalaman dengan Objective C secara umum. Jika Anda berasal dari latar belakang lain, mungkin perlu beberapa saat sebelum Anda benar-benar menginternalisasi aturan manajemen memori - kecuali Anda membuat poin besar darinya.

Ingat, apa pun yang Anda dapatkan dari fungsi alokasi (biasanya metode alokasi statis, tetapi ada beberapa yang lain), atau metode salin, Anda memiliki memori juga dan harus melepaskannya ketika Anda selesai.

Tetapi jika Anda mendapatkan sesuatu kembali dari hal lain termasuk metode pabrik (mis. [NSString stringWithFormat]) Maka Anda akan memiliki referensi autorelease, yang berarti dapat dirilis pada suatu waktu di masa mendatang dengan kode lain - jadi sangat penting bahwa jika Anda memerlukan untuk menyimpannya di luar fungsi langsung yang Anda simpan. Jika tidak, memori mungkin tetap dialokasikan saat Anda menggunakannya, atau dirilis tetapi secara kebetulan masih berlaku, selama pengujian emulator Anda, tetapi lebih cenderung dilepaskan dan muncul sebagai kesalahan akses yang buruk saat dijalankan pada perangkat.

Cara terbaik untuk melacak hal-hal ini, dan ide yang bagus pula (bahkan jika tidak ada masalah yang jelas) adalah menjalankan aplikasi di alat Instrumen, terutama dengan opsi Kebocoran.

philsquared
sumber
2
Saya memiliki beberapa kode sampel accelerometer yang tidak penting untuk aplikasi saya, yang setelah dihapus, menghilangkan kesalahan akses yang buruk. Yang masuk akal mengingat simulator tidak memiliki accelerometer. Saya merasa aneh bahwa kode ini ada, tidak tersentuh, selama seminggu sebelum menyebabkan kesalahan ini ...
Héctor Ramos
Saya baru mengenal Objective-C sehingga sebagian besar masalah saya harus muncul dari manajemen memori. Setelah beberapa tahun di C ++, saya telah menggunakan sebagian besar Java selama tiga atau empat tahun terakhir jadi saya sudah berkarat dalam manajemen memori. Terima kasih atas jawaban anda!
Héctor Ramos
4
Tidak masalah - senang Anda memperbaikinya. Manajemen memori tidak terlalu sulit untuk diraih - Anda hanya perlu memastikan Anda mempelajari aturan dan terbiasa dengan kebiasaan baik.
philsquared
Masalah yang saya miliki tampaknya secara eksklusif dengan terlalu agresif dalam melepaskan string (dan semacamnya) yang saya buat. Saya masih belum 100% yakin tentang apa yang harus dirilis dan kapan, tetapi jawaban Phil jelas membantu.
pluckyglen
Jika saya mengikutinya dengan benar, cmculloh, ya itu adalah hal yang benar untuk dilakukan. Anda tidak memiliki objek yang dikembalikan dari objectAtIndex.
philsquared
101

Penyebab utama EXC_BAD_ACCESS adalah dari mencoba mengakses objek yang dirilis.

Untuk mengetahui cara memecahkan masalah ini, baca dokumen ini: DebuggingAutoReleasePool

Bahkan jika Anda tidak berpikir "melepaskan objek yang dilepaskan secara otomatis", ini akan berlaku untuk Anda.

Metode ini bekerja sangat baik. Saya menggunakannya sepanjang waktu dengan sukses besar !!

Singkatnya, ini menjelaskan cara menggunakan kelas debugging NSZombie Cocoa dan alat baris perintah "malloc_history" untuk menemukan secara tepat objek apa yang dirilis telah diakses dalam kode Anda.

Sidenote:

Menjalankan Instrumen dan memeriksa kebocoran tidak akan membantu memecahkan masalah EXC_BAD_ACCESS. Saya cukup yakin kebocoran memori tidak ada hubungannya dengan EXC_BAD_ACCESS. Definisi kebocoran adalah objek yang tidak dapat Anda akses lagi, dan karena itu Anda tidak dapat menyebutnya.

UPDATE: Saya sekarang menggunakan Instrumen untuk men-debug Kebocoran. Dari Xcode 4.2, pilih Produk-> Profil dan ketika Instrumen diluncurkan, pilih "Zombies".

bentford
sumber
18
Sidenote itu sangat penting. Kebocoran tidak dapat menyebabkan EXC_BAD_ACCESS (mereka memiliki masalah lain). Saya menulis ini untuk mencoba menjernihkan kesalahpahaman tentang EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco
4
Alat zombie di Xcode itu brilian! Saya menemukan pelakunya dalam 3 menit bukan jam.
Aram Kocharyan
1
tautan di atas dalam jawaban tidak tersedia. Menunjukkan 404 tidak ditemukan kesalahan.
Tejas
12

Sinyal EXC_BAD_ACCESS adalah hasil dari melewatkan pointer yang tidak valid ke panggilan sistem. Saya mendapat satu hanya sebelumnya hari ini dengan program uji pada OS X - Saya melewati variabel tidak diinisialisasi pthread_join(), yang disebabkan oleh kesalahan ketik sebelumnya.

Saya tidak terbiasa dengan pengembangan iPhone, tetapi Anda harus memeriksa ulang semua buffer point yang Anda berikan kepada panggilan sistem. Tingkatkan tingkat peringatan kompiler Anda (dengan gcc, gunakan opsi -Walldan -Wextra). Aktifkan sebanyak mungkin diagnostik pada simulator / debugger mungkin.

Adam Rosenfield
sumber
8

Dalam pengalaman saya, ini umumnya disebabkan oleh akses memori ilegal. Periksa semua pointer, terutama pointer objek, untuk memastikan mereka diinisialisasi. Pastikan file MainWindow.xib Anda, jika Anda menggunakannya, diatur dengan benar, dengan semua koneksi yang diperlukan.

Jika tidak ada pemeriksaan di atas kertas yang menghasilkan apa pun, dan itu tidak terjadi ketika satu langkah, coba cari kesalahan dengan pernyataan NSLog (): taburkan kode Anda dengannya, gerakkan di sekitar sampai Anda mengisolasi baris yang menyebabkan kesalahan. Kemudian atur breakpoint pada baris itu dan jalankan program Anda. Ketika Anda mencapai breakpoint, periksa semua variabel, dan objek di dalamnya, untuk melihat apakah ada yang tidak seperti yang Anda harapkan. Saya terutama mengawasi variabel yang kelas objeknya adalah sesuatu yang tidak Anda harapkan. Jika suatu variabel seharusnya berisi UIWindow tetapi memiliki NSNotification di dalamnya sebagai gantinya, kesalahan kode dasar yang sama dapat memanifestasikan dirinya dengan cara yang berbeda ketika debugger tidak beroperasi.

Brent Royal-Gordon
sumber
7

Saya hanya menghabiskan beberapa jam melacak EXC_BAD_ACCESS dan menemukan NSZombies dan vv envv lain tampaknya tidak memberi tahu saya apa pun.

Bagi saya, itu adalah pernyataan NSLog yang bodoh dengan penentu format, tetapi tidak ada argumen yang lolos.

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

Diperbaiki oleh

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);
Scott Heaberlin
sumber
6

Video WWDC 2010 tersedia untuk semua peserta dalam program pengembang apel. Ada video yang luar biasa: "Sesi 311 - Analisis Memori Tingkat Lanjut dengan Instrumen" yang menunjukkan beberapa contoh penggunaan zombie dalam instrumen dan men-debug masalah memori lainnya.

Untuk tautan ke halaman login, klik DI SINI .

Jonah
sumber
6

Bukan jawaban yang lengkap, tetapi satu situasi khusus di mana saya menerima ini adalah ketika mencoba mengakses objek yang 'mati' karena saya mencoba menggunakan autorelease:

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

Jadi misalnya, saya sebenarnya meneruskan ini sebagai objek untuk 'memberi tahu' (mendaftarkannya sebagai pendengar, pengamat, idiom apa pun yang Anda suka) tetapi sudah mati begitu pemberitahuan dikirim dan saya akan mendapatkan EXC_BAD_ACCESS. Mengubahnya ke [[MyNetObject alloc] init]dan melepaskannya nanti jika sesuai menyelesaikan kesalahan.

Alasan lain ini mungkin terjadi adalah misalnya jika Anda memasukkan objek dan mencoba untuk menyimpannya:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Nanti ketika mencoba mengakses myObjectDefinedInHeader Anda mungkin mendapat masalah. Menggunakan:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

mungkin apa yang Anda butuhkan. Tentu saja ini hanya beberapa contoh dari apa yang telah saya temui dan ada alasan lain, tetapi ini dapat membuktikan sulit dipahami sehingga saya menyebutkannya. Semoga berhasil!

rampok
sumber
5

Hanya untuk menambahkan situasi lain di mana ini bisa terjadi:

Saya punya kode:

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

Jelas saya lupa mengalokasikan memori untuk string:

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

memperbaiki masalah.

gnuchu
sumber
Ini tidak menyebabkan kesalahan bagi saya karena string diinisialisasi ke nol dan menggunakan pola objek nol memanggil metode pada nil tidak melakukan apa-apa.
Liron Yahdav
5

Metode lain untuk menangkap pengecualian EXC_BAD_ACCESS sebelum terjadi adalah penganalisa statis , dalam XCode 4+.

Jalankan analisa statis dengan Produk> Analisis (shift + cmd + B). Mengklik pada pesan apa pun yang dihasilkan oleh penganalisa akan menampilkan diagram pada sumber Anda yang menunjukkan urutan mempertahankan / melepaskan objek yang menyinggung.

masukkan deskripsi gambar di sini

ericsoco
sumber
5

Saya merasa berguna untuk menetapkan breakpoint pada objc_exception_throw. Dengan begitu debugger akan rusak ketika Anda mendapatkan EXC_BAD_ACCESS.

Instruksi dapat ditemukan di sini Teknik Debugging

Lyandanderson
sumber
4

Gunakan aturan sederhana "jika Anda tidak mengalokasikan atau menyimpannya, jangan lepaskan".

Gamma-Point
sumber
1
Luaskan aturan itu dengan "... salin ..." dan Anda akan baik-baik saja.
Hingga
4

Cara Mendebug EXC_BAD_ACCESS

Lihat tautan di atas dan lakukan seperti yang tertulis .... Hanya beberapa instruksi cepat untuk menggunakan NSZombies

Jalankan aplikasi dan setelah itu gagal (Seharusnya menampilkan "Terganggu" daripada "EXC_BAD_ACCESS" ... periksa Konsol (Jalankan> Konsol) ... seharusnya ada pesan di sana sekarang memberitahukan objek apa yang coba diakses.

-Ben

Ben Call
sumber
3

Saya telah men-debug, dan kode refactoring untuk menyelesaikan kesalahan ini selama empat jam terakhir. Sebuah posting di atas membuat saya melihat masalah:

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

Properti setelah: startPoint = [[Alokasi DataPoint] init]; startPoint = [[DataPointList objectAtIndex: 0] retain];

Selamat tinggal EXC_BAD_ACCESS


sumber
Saya membuat kesalahan serupa. Saya lupa mengingat contoh yang menyebabkan crash dan saya menghabiskan waktu berjam-jam untuk mencari tahu. Pengalaman Anda menyalakan saya untuk mencari tahu milikku. Terima kasih!
David.Chu.ca
3

Semoga Anda melepaskan 'string' setelah selesai!


sumber
3

Saya lupa mengembalikan diri dengan init-Method ...;)

denbec
sumber
Ini harus berupa peringatan waktu kesalahan / kesalahan dan bukan EXC_BAD_ACCESS selama runtime.
stigi
3

Ini adalah utas yang sangat bagus. Inilah pengalaman saya: Saya mengacaukan kata kunci retain / assign pada deklarasi properti. Saya bilang:

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

di mana saya seharusnya mengatakan

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
orang bodoh
sumber
1
Aneh, mengapa Anda harus mempertahankan IBOutlet? Manajemen mereka dilakukan untuk Anda secara otomatis.
jv42
3

Saya menemukan EXC_BAD_ACCESS di iPhone hanya ketika mencoba mengeksekusi metode C yang menyertakan array besar. Simulator itu mampu memberi saya cukup memori untuk menjalankan kode, tetapi bukan perangkat (array adalah satu juta karakter, jadi itu sedikit berlebihan!).

EXC_BAD_ACCESS terjadi tepat setelah titik masuk dari metode ini, dan membuat saya bingung untuk beberapa saat karena itu tidak ada di dekat deklarasi array.

Mungkin orang lain akan mendapat manfaat dari beberapa jam mencabuti rambutku.

mblackwell8
sumber
3

Lupa mengambil pointer yang tidak dialokasikan dari dealloc. Saya mendapatkan exc_bad_access di rootView saya dari UINavigationController, tetapi hanya kadang-kadang. Saya berasumsi bahwa masalahnya ada di rootView karena terhenti di tengah-tengah viewDidAppear {}. Ternyata hanya terjadi setelah saya membuka tampilan dengan rilis dealloc buruk {}, dan hanya itu!

"EXC_BAD_ACCESS" [Beralih ke proses 330] Tidak ada memori untuk diprogram sekarang: tidak aman untuk memanggil malloc

Saya pikir itu adalah masalah di mana saya mencoba untuk mengalokasikan ... bukan di mana saya mencoba untuk melepaskan non-alokasi, D'oh!

Josh
sumber
3

Bagaimana saya berurusan dengan EXC_BAD_ACCESS

Terkadang saya merasa bahwa ketika kesalahan EXC_BAD_ACCESS dilemparkan xcode akan menampilkan kesalahan di kelas main.m. Tidak memberikan informasi tambahan di mana crash terjadi (Kadang-kadang).

Pada saat-saat itu kita dapat mengatur Breakpoint Luar Biasa di Xcode sehingga ketika pengecualian tertangkap breakpoint akan ditempatkan dan akan secara langsung intim dengan pengguna bahwa crash telah terjadi di baris itu

masukkan deskripsi gambar di sini

iPrabu
sumber
2

Panggilan NSAssert () untuk memvalidasi parameter metode cukup berguna untuk melacak dan menghindari melewati nil juga.

Ryan Townshend
sumber
2

Saya baru saja mengalami masalah ini. Bagi saya alasannya menghapus objek yang dikelola CoreData dan mencoba membacanya setelah itu dari tempat lain.

Konryd
sumber
2

Saya telah men-debug, dan kode refactoring untuk menyelesaikan kesalahan ini selama empat jam terakhir. Sebuah posting di atas membuat saya melihat masalah:

Properti sebelum:

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

Properti setelah:

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

Selamat tinggal EXC_BAD_ACCESS

Terima kasih banyak atas jawaban Anda. Saya telah berjuang dengan masalah ini sepanjang hari. Kamu luar biasa!


sumber
4
Bukankah Anda langsung menimpa titik awal? Saya kira Anda tidak perlu baris pertama itu sama sekali.
toxaq
2
Sama sekali tidak perlu mengalokasikan dan menginisialisasi variabel jika Anda akan segera menimpanya dengan yang lain. Anda baru saja membocorkan objek pada tugas pertama.
dreamlax
2

Hanya untuk menambahkan

Lynda.com memiliki DVD fantastis yang disebut

Pelatihan iPhone SDK Essential

dan Bab 6, Pelajaran 3 adalah tentang EXEC_BAD_ACCESS dan bekerja dengan Zombies.

Itu bagus untuk saya mengerti, bukan hanya kode kesalahan tetapi bagaimana saya bisa menggunakan Zombies untuk mendapatkan lebih banyak info tentang objek yang dirilis.

balexandre
sumber
2

Untuk memeriksa kesalahan apa yang mungkin terjadi

Gunakan NSZombieEnabled.

Untuk mengaktifkan fasilitas NSZombieEnabled di aplikasi Anda:

Pilih Project> Edit Active Executable untuk membuka jendela Info yang dapat dieksekusi. Klik Argumen. Klik tombol tambah (+) di bagian “Variabel yang akan diatur di lingkungan”. Masukkan NSZombieEnabled di kolom Nama dan YES di kolom Nilai. Pastikan tanda centang untuk entri NSZombieEnabled dipilih.

Saya menemukan jawaban ini di iPhoneSDK

zambono
sumber
2

Saya menyadari ini ditanya beberapa waktu lalu, tetapi setelah membaca utas ini, saya menemukan solusi untuk XCode 4.2: Produk -> Edit Skema -> Tab Diagnostik -> Aktifkan Objek Zombie

Membantu saya menemukan pesan yang dikirim ke objek yang tidak dialokasikan.

Sean Aitken
sumber
2

Ketika Anda memiliki rekursi tak terbatas, saya pikir Anda juga dapat memiliki kesalahan ini. Ini adalah kasus bagi saya.

coolcool1994
sumber
1

Bahkan kemungkinan lain: menggunakan blok dalam antrian, mungkin dengan mudah terjadi bahwa Anda mencoba mengakses objek dalam antrian lain, yang sudah tidak dialokasikan pada saat ini. Biasanya ketika Anda mencoba mengirim sesuatu ke GUI. Jika breakpoint pengecualian Anda diatur di tempat yang aneh, maka ini mungkin penyebabnya.

brainray
sumber
1

Saya mendapatkannya karena saya tidak menggunakan [self performSegueWithIdentifier:sender:]dan -(void) prepareForSegue:(UIstoryboardSegue *)benar

DHShah01
sumber
1

Jangan lupa @simbol saat membuat string, perlakukan C-stringssesuai NSStringskeinginan EXC_BAD_ACCESS.

Gunakan ini:

@"Some String"

Daripada ini:

"Some String"

PS - biasanya ketika mengisi konten arraydengan banyak catatan.

Artur
sumber