2010-11-02 20 views
6

Trình gỡ rối của tôi bị hỏng hoặc có điều gì đó cơ bản mà tôi không hiểu.Simple Objective-C over-release rằng * nên * crash không bị lỗi. Tại sao?

Tôi có một số mã rất cơ bản trong một chương trình dòng lệnh rất cơ bản là nên lỗi. Tuy nhiên, nó không bị rơi.

int main (int argc, const char * argv[]) 
{ 
    NSString *string = [[NSString alloc] initWithString:@"Hello"]; 

    [string release]; 

    NSLog(@"Length: %d", [string length]); 

    return 0; 
} 

Bản ghi nhật ký in "Độ dài: 5" như bạn mong đợi cho chuỗi hợp lệ. Tuy nhiên, chuỗi nên được deallocated bởi điểm đó và một lỗi exec_bad_access nên được ném.

Tôi đã thử mã này với trình gỡ lỗi được đính kèm và không kèm theo trình gỡ lỗi - cả hai đều cho kết quả tương tự. Tôi cũng đã kích hoạt (và vô hiệu hóa) NSZombie, mà dường như không có hiệu lực (ban đầu tôi nghĩ rằng đây là vấn đề, vì NSZombie đối tượng không bao giờ được deallocated - nhưng nó vẫn không sụp đổ với NSZombie vô hiệu hóa).

Tôi có điểm ngắt được đặt trong tệp .gdbinit cục bộ của mình để chia nhỏ những thứ như -[NSException raise]objc_exception_throw. Tôi cũng có các điểm ngắt được đặt trên nhiều phương thức trên NSZombie để bắt chúng.

fb -[NSException raise] 
fb -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] 
fb -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 

#define NSZombies 
# this will give you help messages. Set to NO to turn them off. 
set env MallocHelp=YES 
# might also be set in launch arguments. 
set env NSZombieEnabled=YES 
set env NSDeallocateZombies=NO 
set env MallocCheckHeapEach=100000 
set env MallocCheckHeapStart=100000 
set env MallocScribble=YES 
set env MallocGuardEdges=YES 
set env MallocCheckHeapAbort=1 

set env CFZombie 5 

fb -[_NSZombie init] 
fb -[_NSZombie retainCount] 
fb -[_NSZombie retain] 
fb -[_NSZombie release] 
fb -[_NSZombie autorelease] 
fb -[_NSZombie methodSignatureForSelector:] 
fb -[_NSZombie respondsToSelector:] 
fb -[_NSZombie forwardInvocation:] 
fb -[_NSZombie class] 
fb -[_NSZombie dealloc] 

fb szone_error 
fb objc_exception_throw 

Với những breakpoint thiết lập và NSZombie kích hoạt, tôi sẽ nhận được một cái gì đó giống như [NSString length]: message sent to deallocated instance 0x100010d39 in ra cửa sổ Console, nhưng tôi không thấy điều này. Tôi thấy chiều dài NSLog in là 5.

Tôi thấy hành vi tương tự với các lớp khác như NSURLNSNumber. Nhưng một số lớp học bị hỏng như mong đợi, chẳng hạn như NSErrorNSObject.

Điều này có liên quan gì đến các cụm lớp không? Họ không tuân theo các quy tắc tương tự liên quan đến quản lý bộ nhớ?

Nếu nhóm lớp không liên quan đến vấn đề này, tính năng phổ biến duy nhất tôi có thể thấy là các lớp không bị hỏng theo cách này đều là cầu nối miễn phí với đối tác Core Foundation. Điều này có thể có cái gì để làm với nó?

+0

Tôi đã tự hỏi bản thân mình một thời gian trước đây, đã thấy cùng một 'vấn đề'/hành vi. Hy vọng ai đó có thể giải thích điều này. – Rits

+0

Bộ sưu tập rác không phải là ngay lập tức? :) – willcodejavaforfood

+1

Đó không phải là vấn đề. Trong môi trường thu thập rác, một lời gọi rõ ràng để 'phát hành' hoàn toàn không có gì. – Yuji

Trả lời

4

retain/release là hợp đồng giữa API và lập trình viên khi bạn tuân thủ quy tắc, nó không bị lỗi. Hợp đồng không đảm bảo rằng nếu bạn không tuân theo quy tắc, nó sẽ sụp đổ!

Trong trường hợp này,

[[NSString alloc] initWithString:@"Hello"] 

chỉ trả về đối tượng giống như @"Hello" như một tối ưu hóa. Hằng số NSString không bao giờ được phân phối; làm tối ưu hóa, retainrelease (tôi nghĩ) bị bỏ qua. Đó là lý do tại sao nó không sụp đổ.

Bạn có thể kiểm tra dự đoán của mình bằng cách so sánh giá trị con trỏ của @"Hello"string.

+0

Ok, điều đó hợp lý với tôi. Điều gì sẽ xảy ra nếu tôi đã thực hiện '[[NSString alloc] init];' trái ngược với việc initing với một chuỗi không đổi? Trong thử nghiệm của tôi, nó vẫn thể hiện hành vi tương tự như sử dụng chuỗi không đổi, điều này có được mong đợi không? Và những trường hợp khác mà tôi thấy hành vi tương tự, chẳng hạn như với 'NSURL' và' NSNumber' thì sao? – Jasarien

+0

Và có, bạn là chính xác, chuỗi và @ "Hello" cả hai điểm đến cùng một vị trí. Điều đó làm rõ điều đó. Tôi vẫn còn bối rối về các trường hợp khác mặc dù. – Jasarien

+0

'[[NSString alloc] init]' trả về một chuỗi rỗng được chia sẻ, mà lại không bao giờ bị hủy. Không có gì đảm bảo rằng mỗi lệnh gọi tới '[[SomeClass alloc] init]' cho một cá thể riêng biệt. Hợp đồng là nếu bạn tuân theo quy tắc lưu giữ/giải phóng, chương trình không bị lỗi. Không có gì nhiều hơn thế. – Yuji

1

Đây là một ví dụ tuyệt vời về lý do tại sao giữ lại số lượng là một công cụ gỡ lỗi khá vô ích. Đó là một sai lầm để giả định -retain và -release luôn luôn thêm hoặc loại bỏ 1 từ số lượng giữ lại và số lượng giữ lại là những gì bạn nghĩ rằng nó nên được.

Hãy thử

NSString *string = [[NSString alloc] initWithFormat:@"Hello %d", argc]; 

Điều đó sẽ cung cấp cho bạn một chuỗi đó sẽ cư xử giống như cách bạn đang mong đợi kể từ khi bạn không initialising chuỗi của bạn từ một thời gian liên tục biên dịch. Tuy nhiên, được cảnh báo, với zombie được kích hoạt, bạn sẽ nhận được hành vi mà bạn mong đợi nhưng không có zombie, NSLog có thể hoạt động tốt. Mặc dù chuỗi đã được deallocated, các dữ liệu trong đối tượng vẫn còn đó trong bộ nhớ để lại một "con ma" mà sẽ trả lời một cách chính xác cho một số tin nhắn.

Các vấn đề liên quan