Đã nhận được tín hiệu EXC_BAD_ACCESS


290

Khi triển khai ứng dụng cho thiết bị, chương trình sẽ thoát sau một vài chu kỳ với lỗi sau:

Program received signal: "EXC_BAD_ACCESS".

Chương trình chạy mà không có bất kỳ vấn đề nào trên trình giả lập iPhone, nó cũng sẽ gỡ lỗi và chạy miễn là tôi thực hiện từng bước một. Ngay khi tôi để nó chạy lại, tôi sẽ nhấn EXC_BAD_ACCESStín hiệu.

Trong trường hợp cụ thể này, nó đã xảy ra lỗi trong mã gia tốc. Nó sẽ không thực thi trong trình giả lập, đó là lý do tại sao nó không đưa ra bất kỳ lỗi nào. Tuy nhiên, nó sẽ thực thi một khi được triển khai cho thiết bị.

Hầu hết các câu trả lời cho câu hỏi này đều liên quan đến EXC_BAD_ACCESSlỗi chung , vì vậy tôi sẽ để nó mở dưới dạng bắt tất cả cho lỗi Truy cập xấu đáng sợ.

EXC_BAD_ACCESSthường được ném là kết quả của việc truy cập bộ nhớ bất hợp pháp. Bạn có thể tìm thêm thông tin trong các câu trả lời dưới đây.

Bạn đã gặp EXC_BAD_ACCESStín hiệu trước đó, và làm thế nào bạn đối phó với nó?

Câu trả lời:


196

Từ mô tả của bạn, tôi nghi ngờ lời giải thích rất có thể là bạn có một số lỗi trong quản lý bộ nhớ. Bạn nói rằng bạn đã làm việc về phát triển iPhone trong một vài tuần, nhưng không biết bạn có kinh nghiệm với Objective C nói chung hay không. Nếu bạn đến từ một nền tảng khác, có thể mất một chút thời gian trước khi bạn thực sự nội tâm hóa các quy tắc quản lý bộ nhớ - trừ khi bạn đưa ra quan điểm lớn về nó.

Hãy nhớ rằng, bất cứ điều gì bạn nhận được từ một hàm phân bổ (thường là phương thức cấp phát tĩnh, nhưng có một vài phương thức khác) hoặc phương thức sao chép, bạn cũng sở hữu bộ nhớ và phải giải phóng nó khi bạn hoàn thành.

Nhưng nếu bạn nhận được một cái gì đó từ bất kỳ thứ gì khác, kể cả các phương thức của nhà máy (ví dụ [NSString stringWithFormat]) thì bạn sẽ có một tài liệu tham khảo tự động, có nghĩa là nó có thể được phát hành vào một lúc nào đó trong tương lai bởi mã khác - vì vậy điều quan trọng là nếu bạn cần để giữ cho nó xung quanh ngoài chức năng ngay lập tức mà bạn giữ nó. Nếu bạn không, bộ nhớ có thể vẫn được phân bổ trong khi bạn đang sử dụng hoặc được giải phóng nhưng vẫn trùng hợp, trong quá trình kiểm tra trình giả lập của bạn, nhưng nhiều khả năng sẽ được giải phóng và hiển thị là lỗi truy cập xấu khi chạy trên thiết bị.

Cách tốt nhất để theo dõi những điều này và dù sao đi nữa (ngay cả khi không có vấn đề rõ ràng nào) là chạy ứng dụng trong công cụ Dụng cụ, đặc biệt là với tùy chọn Leaks.


2
Tôi đã có một số mã lấy mẫu gia tốc không quan trọng đối với ứng dụng của mình, sau khi gỡ bỏ, đã loại bỏ lỗi truy cập xấu. Điều này hợp lý khi xem xét trình giả lập không có gia tốc kế. Tôi thấy thật kỳ lạ khi mã này tồn tại, chưa được xử lý, trong một tuần trước khi gây ra lỗi này ...
Héctor Ramos

Tôi chưa quen với Objective-C nên hầu hết các vấn đề của tôi phát sinh từ việc quản lý bộ nhớ. Sau một vài năm trong C ++, tôi đã sử dụng phần lớn Java trong ba hoặc bốn năm qua vì vậy tôi đã trở nên khó khăn trong việc quản lý bộ nhớ. Cảm ơn câu trả lời của bạn!
Héctor Ramos

4
Không có vấn đề - rất vui vì bạn đã sửa nó. Việc quản lý bộ nhớ không thực sự khó khăn để vượt lên - bạn chỉ cần đảm bảo rằng bạn học được các quy tắc và tập thói quen tốt.
philsquared

Vấn đề mà tôi gặp phải dường như chỉ là quá tích cực trong việc phát hành các chuỗi (và như vậy) mà tôi tạo ra. Tôi vẫn không chắc chắn 100% về những gì nên được phát hành và khi nào, nhưng câu trả lời của Phil chắc chắn có ích.
pluckyglen

Nếu tôi làm theo đúng, cmculloh, vâng đó là điều đúng đắn. Bạn không sở hữu trả về đối tượng từ objectAt Index.
philsquared

101

Một nguyên nhân chính của EXC_BAD_ACCESS là do cố gắng truy cập các đối tượng được phát hành.

Để tìm hiểu cách khắc phục sự cố này, hãy đọc tài liệu này: DebuggingAutoReleasePool

Ngay cả khi bạn không nghĩ rằng mình đang "phát hành các đối tượng tự động phát hành", điều này sẽ áp dụng cho bạn.

Phương pháp này hoạt động cực kỳ tốt. Tôi sử dụng nó mọi lúc với thành công lớn !!

Tóm lại, điều này giải thích cách sử dụng lớp gỡ lỗi NSZombie của Cốc Cốc và công cụ dòng lệnh "malloc_history" để tìm chính xác đối tượng đã phát hành đã được truy cập trong mã của bạn.

Sidenote:

Chạy dụng cụ và kiểm tra rò rỉ sẽ không giúp khắc phục sự cố EXC_BAD_ACCESS. Tôi khá chắc chắn rò rỉ bộ nhớ không liên quan gì đến EXC_BAD_ACCESS. Định nghĩa về rò rỉ là một đối tượng mà bạn không còn có quyền truy cập và do đó bạn không thể gọi nó.

CẬP NHẬT: Bây giờ tôi sử dụng Dụng cụ để gỡ lỗi Rò rỉ. Từ Xcode 4.2, chọn Sản phẩm-> Hồ sơ và khi Dụng cụ khởi chạy, chọn "Thây ma".


18
Sidenote đó là rất quan trọng. Rò rỉ không thể gây ra EXC_BAD_ACCESS (họ có vấn đề khác). Tôi đã viết bài này để cố gắng xóa bỏ những quan niệm sai lầm về EXC_BAD_ACCESS loufranco.com/blog/files/Under Hiểu
Lou Franco

4
Công cụ zombie trong Xcode thật tuyệt vời! Tôi tìm thấy thủ phạm trong 3 phút chứ không phải vài giờ.
Aram Kocharyan

1
ở trên liên kết trong câu trả lời không có sẵn. Hiển thị lỗi 404 không tìm thấy.
Tejas

12

Tín hiệu EXC_BAD_ACCESS là kết quả của việc chuyển một con trỏ không hợp lệ cho một cuộc gọi hệ thống. Tôi đã nhận được một cái ngay hôm nay với một chương trình thử nghiệm trên OS X - Tôi đã chuyển một biến chưa được khởi tạo sang pthread_join(), đó là do một lỗi đánh máy trước đó.

Tôi không quen với việc phát triển iPhone, nhưng bạn nên kiểm tra kỹ tất cả các con trỏ bộ đệm mà bạn đang chuyển đến các cuộc gọi hệ thống. Làm tăng mức cảnh báo của trình biên dịch của bạn mọi cách (với gcc, sử dụng -Wall-Wextracác tùy chọn). Cho phép càng nhiều chẩn đoán trên trình giả lập / gỡ lỗi càng tốt.


8

Theo kinh nghiệm của tôi, điều này thường được gây ra bởi truy cập bộ nhớ bất hợp pháp. Kiểm tra tất cả các con trỏ, đặc biệt là các con trỏ đối tượng, để đảm bảo chúng được khởi tạo. Đảm bảo tệp MainWindow.xib của bạn, nếu bạn đang sử dụng một tệp, được thiết lập đúng, với tất cả các kết nối cần thiết.

Nếu không có kiểm tra trên giấy nào bật lên bất cứ điều gì và điều đó không xảy ra khi một bước, hãy thử xác định lỗi với các câu lệnh NSLog (): rắc mã của bạn với chúng, di chuyển chúng cho đến khi bạn tách dòng đó gây ra lỗi. Sau đó đặt điểm dừng trên dòng đó và chạy chương trình của bạn. Khi bạn đạt điểm dừng, hãy kiểm tra tất cả các biến và các đối tượng trong đó, để xem liệu có bất cứ điều gì không giống như bạn mong đợi hay không. Tôi đặc biệt chú ý đến các biến có lớp đối tượng là điều bạn không mong đợi. Nếu một biến được cho là chứa UIWindow nhưng nó có NSNotification trong đó, thì lỗi mã cơ bản tương tự có thể tự biểu hiện theo một cách khác khi trình gỡ lỗi không hoạt động.


7

Tôi chỉ mất vài giờ để theo dõi một EXC_BAD_ACCESS và thấy NSZombie và các vv env khác dường như không cho tôi biết bất cứ điều gì.

Đối với tôi, đó là một câu lệnh NSLog ngu ngốc với các bộ định dạng định dạng nhưng không có đối số nào được thông qua.

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

Được sửa chữa bởi

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

6

Các video WWDC 2010 có sẵn cho bất kỳ người tham gia chương trình nhà phát triển apple. Có một video tuyệt vời: "Phiên 311 - Phân tích bộ nhớ nâng cao với các công cụ" cho thấy một số ví dụ về việc sử dụng zombie trong các công cụ và gỡ lỗi các vấn đề bộ nhớ khác.

Đối với một liên kết đến trang đăng nhập bấm vào ĐÂY .


6

Không phải là một câu trả lời hoàn chỉnh, nhưng một tình huống cụ thể mà tôi đã nhận được điều này là khi cố gắng truy cập một đối tượng 'đã chết' vì tôi đã cố gắng sử dụng chế độ tự động:

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

Vì vậy, ví dụ, tôi thực sự đã chuyển nó dưới dạng một đối tượng để 'thông báo' (đã đăng ký nó như một người nghe, người quan sát, bất cứ thành ngữ nào bạn thích) nhưng nó đã chết sau khi thông báo được gửi và tôi nhận được EXC_BAD_ACCESS. Thay đổi nó [[MyNetObject alloc] init]và phát hành nó sau khi thích hợp đã giải quyết lỗi.

Một lý do khác điều này có thể xảy ra là ví dụ nếu bạn truyền vào một đối tượng và cố gắng lưu trữ nó:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Sau này khi cố gắng truy cập myObjectDefinedInHeader, bạn có thể gặp rắc rối. Sử dụng:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

có thể là những gì bạn cần. Tất nhiên đây chỉ là một vài ví dụ về những gì tôi đã gặp phải và có những lý do khác, nhưng những điều này có thể chứng minh khó nắm bắt nên tôi đề cập đến chúng. Chúc may mắn!


5

Chỉ cần thêm một tình huống khác, nơi điều này có thể xảy ra:

Tôi đã có mã:

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

Rõ ràng là tôi đã quên phân bổ bộ nhớ cho chuỗi:

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

khắc phục sự cố.


Điều này không gây ra bất kỳ lỗi nào cho tôi vì chuỗi được khởi tạo thành nil và sử dụng mẫu đối tượng null gọi một phương thức trên nil không làm gì cả.
Liron Yahdav

5

Một phương pháp khác để bắt ngoại lệ EXC_BAD_ACCESS trước khi chúng xảy ra là máy phân tích tĩnh , trong XCode 4+.

Chạy bộ phân tích tĩnh với Sản phẩm> Phân tích (shift + cmd + B). Nhấp vào bất kỳ thông báo nào do trình phân tích tạo ra sẽ phủ lên sơ đồ trên nguồn của bạn hiển thị chuỗi các lần giữ lại / phát hành của đối tượng vi phạm.

nhập mô tả hình ảnh ở đây


5

Tôi thấy hữu ích khi đặt điểm dừng trên objc_exception_throw. Bằng cách đó, trình gỡ lỗi sẽ bị hỏng khi bạn nhận được EXC_BAD_ACCESS.

Hướng dẫn có thể được tìm thấy ở đây DebuggingT kỹ thuật


4

Sử dụng quy tắc đơn giản "nếu bạn không phân bổ hoặc giữ lại, đừng giải phóng nó".


1
Mở rộng quy tắc đó bằng cách "... sao chép nó ..." và bạn sẽ ổn thôi.
Đến

4

Cách gỡ lỗi EXC_BAD_ACCESS

Kiểm tra liên kết ở trên và làm như nó nói .... Chỉ cần một số hướng dẫn nhanh để sử dụng NSZombie

Chạy ứng dụng và sau khi nó không thành công (Nên hiển thị "Bị gián đoạn" thay vì "EXC_BAD_ACCESS" ... hãy kiểm tra Bảng điều khiển (Chạy> Bảng điều khiển) ... hiện tại sẽ có thông báo cho biết đối tượng nào đang cố truy cập.

-Ben


3

Tôi đã gỡ lỗi và tái cấu trúc mã để giải quyết lỗi này trong bốn giờ qua. Một bài viết ở trên đã dẫn tôi đến vấn đề:

Thuộc tính trước: startPoint = [[DataPoint alloc] init]; startPoint = [Đối tượng DataPointListAt Index: 0];
. . . x = startPoint.x - 10; // EXC_BAD_ACCESS

Thuộc tính sau: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAt Index: 0] giữ lại];

Tạm biệt EXC_BAD_ACCESS


Tôi đã phạm sai lầm tương tự. Tôi đã quên thực hiện lại trường hợp gây ra sự cố và tôi đã dành hàng giờ để tìm ra nó. Kinh nghiệm của bạn thắp sáng tôi để tìm ra của tôi. Cảm ơn!
David.Chu.ca

3

Hy vọng bạn sẽ phát hành 'chuỗi' khi bạn hoàn thành!


3

Tôi đã quên trả lại bản thân trong một phương thức init ...;)


Đây phải là một cảnh báo / lỗi thời gian biên dịch và không phải là EXC_BAD_ACCESS trong thời gian chạy.
stigi

3

Đây là một chủ đề tuyệt vời. Đây là kinh nghiệm của tôi: Tôi đã nhầm lẫn với từ khóa giữ / gán trên một tờ khai tài sản. Tôi đã nói:

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

tôi nên nói ở đâu

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

1
Lạ thật, tại sao bạn lại cần giữ lại IBOutlet? Quản lý của họ được thực hiện cho bạn tự động.
jv42

3

Tôi chỉ gặp EXC_BAD_ACCESS trên iPhone khi đang cố thực hiện phương thức C bao gồm một mảng lớn. Trình mô phỏng đã có thể cung cấp cho tôi đủ bộ nhớ để chạy mã, nhưng không phải thiết bị (mảng là một triệu ký tự, vì vậy nó là quá nhiều!).

EXC_BAD_ACCESS xảy ra ngay sau điểm vào của phương thức và khiến tôi bối rối trong một thời gian vì nó không ở gần khai báo mảng.

Có lẽ ai đó khác có thể được hưởng lợi từ vài giờ nhổ tóc của tôi.


3

Quên lấy ra một con trỏ không được phân bổ từ dealloc . Tôi đã nhận được exc_bad_access trên rootView của tôi về một UINavestionControll, nhưng chỉ đôi khi. Tôi giả sử vấn đề là ở rootView vì nó đã bị sập giữa chừng viewDidAppear {}. Hóa ra chỉ xảy ra sau khi tôi bật chế độ xem với bản phát hành dealloc {} tồi, và chỉ có thế!

"EXC_BAD_ACCESS" [Chuyển sang xử lý 330] Hiện không có bộ nhớ để lập trình: không an toàn để gọi malloc

Tôi nghĩ đó là một vấn đề khi tôi cố gắng phân bổ ... không phải là nơi tôi đang cố gắng giải phóng một người không phân bổ, D'oh!


3

Cách tôi đối phó với EXC_BAD_ACCESS

Đôi khi tôi cảm thấy rằng khi một lỗi EXC_BAD_ACCESS được ném xcode sẽ hiển thị lỗi trong lớp main.m không cung cấp thêm thông tin về nơi xảy ra sự cố (Đôi khi).

Trong những thời điểm đó, chúng ta có thể đặt Điểm dừng đặc biệt trong Xcode để khi ngoại lệ bị bắt, điểm dừng sẽ được đặt và sẽ trực tiếp thân mật với người dùng rằng sự cố đã xảy ra trong dòng đó

nhập mô tả hình ảnh ở đây


2

Các lệnh gọi NSAssert () để xác thực các tham số phương thức khá tiện dụng để theo dõi và cũng tránh được các nils.


2

Tôi chỉ có vấn đề này. Đối với tôi lý do là xóa một đối tượng được quản lý CoreData và cố gắng đọc nó sau đó từ một nơi khác.


2

Tôi đã gỡ lỗi và tái cấu trúc mã để giải quyết lỗi này trong bốn giờ qua. Một bài viết ở trên đã dẫn tôi đến vấn đề:

Tài sản trước:

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

Tài sản sau:

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

Tạm biệt EXC_BAD_ACCESS

Cảm ơn bạn rất nhiều cho câu trả lời của bạn. Tôi đã phải vật lộn với vấn đề này cả ngày. Bạn thật tuyệt vời!


4
Không phải bạn vừa ghi đè ngay lập tức startpoint? Tôi không nghĩ bạn cần dòng đầu tiên đó.
toxaq

2
Hoàn toàn không cần phân bổ và khởi tạo một biến nếu bạn ngay lập tức ghi đè lên nó bằng biến khác. Bạn chỉ bị rò rỉ đối tượng trong nhiệm vụ đầu tiên.
dreamlax

2

Chỉ cần thêm

Lynda.com có một DVD tuyệt vời được gọi là

Đào tạo thiết yếu SDK iPhone

và Chương 6, Bài 3 là tất cả về EXEC_BAD_ACCESS và làm việc với Zombies.

Thật tuyệt vời đối với tôi để hiểu, không chỉ mã lỗi mà tôi có thể sử dụng Zombies để có thêm thông tin về đối tượng được phát hành.


2

Để kiểm tra lỗi có thể là gì

Sử dụng NSZombieEnables.

Để kích hoạt tiện ích NSZombieEnables trong ứng dụng của bạn:

Chọn Project> Edit Active Executable để mở cửa sổ Thông tin thực thi. Nhấp vào đối số. Nhấp vào nút add (+) trong Biến Biến được đặt trong phần môi trường. Nhập NSZombieEnables trong cột Tên và CÓ trong cột Giá trị. Đảm bảo rằng dấu kiểm cho mục NSZombieEnables được chọn.

Tôi tìm thấy câu trả lời này trên iPhoneSDK


2

Tôi nhận ra điều này đã được hỏi cách đây một thời gian, nhưng sau khi đọc chủ đề này, tôi đã tìm thấy giải pháp cho XCode 4.2: Sản phẩm -> Chỉnh sửa lược đồ -> Tab chẩn đoán -> Kích hoạt đối tượng Zombie

Giúp tôi tìm thấy một tin nhắn được gửi đến một đối tượng bị xử lý.


2

Khi bạn có đệ quy vô hạn, tôi nghĩ bạn cũng có thể có lỗi này. Đây là một trường hợp đối với tôi.


1

Thậm chí một khả năng khác: sử dụng các khối trong hàng đợi, có thể dễ dàng xảy ra việc bạn cố gắng truy cập một đối tượng trong hàng đợi khác, đã được phân bổ lại tại thời điểm này. Thông thường khi bạn cố gắng gửi một cái gì đó đến GUI. Nếu điểm dừng ngoại lệ của bạn đang được đặt ở một nơi xa lạ, thì đây có thể là nguyên nhân.


1

Tôi đã nhận nó bởi vì tôi đã không sử dụng [self performSegueWithIdentifier:sender:]-(void) prepareForSegue:(UIstoryboardSegue *)đúng


1

Đừng quên @biểu tượng khi tạo chuỗi, coi C-stringsnhư NSStringssẽ gây ra EXC_BAD_ACCESS.

Dùng cái này:

@"Some String"

Thay vì điều này:

"Some String"

PS - thường là khi điền nội dung của một arrayvới rất nhiều hồ sơ.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.