为什么我可以将消息发送到NSArray的解除分配的实例? [英] Why can I send messages to a deallocated instance of NSArray?
问题描述
我刚注意到 NSArray
的惊人行为,这就是我发布此问题的原因。
I just noticed a surprising behavior of NSArray
, that's why I'm posting this question.
I刚刚添加了一个方法:
I just added a method like:
- (IBAction) crashOrNot
{
NSArray *array = [[NSArray alloc] init];
array = [[NSArray alloc] init];
[array release];
[array release];
}
理论上这段代码会崩溃。但在我的情况下它永远不会崩溃!!!
Theoretically this code will crash. But In my case it never crashed !!!
我用 NSMutableArray更改了
但这次应用程序崩溃了。 NSArray
为什么会发生这种情况,为什么 NSArray
没有崩溃而 NSMutableArray
崩溃?
I changed the NSArray
with NSMutableArray
but this time the app crashed.
Why this happens, why NSArray
not crashing and NSMutableArray
crashes ?
推荐答案
通常,当您释放一个对象时,内存不会被清零,只需要任何需要它的人都可以自由地回收它。因此,如果保留指向解除分配对象的指针,通常仍可以使用该对象一段时间(就像使用第二个 -release
消息一样)。示例代码:
In general, when you deallocate an object the memory is not zeroed out, it’s just free to be reclaimed by whoever needs it. Therefore if you keep a pointer to the deallocated object, you can usually still use the object for some time (like you do with your second -release
message). Sample code:
#import <Foundation/Foundation.h>
@interface Foo : NSObject
@property(assign) NSUInteger canary;
@end
@implementation Foo
@synthesize canary;
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
Foo *foo = [[Foo alloc] init];
[foo setCanary:42];
[foo release];
NSLog(@"%li", [foo canary]); // 42, no problem
}
return 0;
}
默认情况下没有对此进行检查,行为是未定义的。如果设置 NSZombieEnabled
环境值,消息传递代码将开始检查已解除分配的对象,并应在您的情况下抛出异常,就像您预期的那样:
There are no checks against this by default, the behaviour is simply undefined. If you set the NSZombieEnabled
environment value, the messaging code starts checking for deallocated objects and should throw an exception in your case, just as you probably expected:
*** -[Foo canary]: message sent to deallocated instance 0x100108250
顺便说一句,默认的,未经检查的情况是内存错误难以调试的原因之一,因为行为可能是高度不确定的(取决于内存使用情况)模式)。您可能会在代码周围出现奇怪的错误,而错误是在其他地方过度释放的对象。继续前面的例子:
By the way, the default, unchecked case is one of the reasons why memory errors are so hard to debug, because the behaviour might be highly non-deterministic (it depends on memory usage patterns). You might get strange errors here and there around the code, while the bug is an over-released object somewhere else. Continuing in the previous example:
Foo *foo = [[Foo alloc] init];
[foo setCanary:42];
[foo release];
Foo *bar = [[Foo alloc] init];
[bar setCanary:11];
NSLog(@"%li", [foo canary]); // 11, magic! (Not guaranteed.)
至于为什么 NSArray
与 NSMutableArray
不同,一个空数组看起来确实像一个特殊的野兽:
As for why is NSArray
different from NSMutableArray
, an empty array looks like a special beast indeed:
NSArray *foo = [[NSArray alloc] init];
NSArray *bar = [[NSArray alloc] init];
NSLog(@"%i", foo == bar); // yes, they point to the same object
所以这可能与它有关。但在一般情况下,使用解除分配的对象可能会做任何事情。它可能会起作用,也可能不起作用,它可能会泄漏你的咖啡或开始核战争。不要这样做。
So that might have something to do with it. But in general case, working with deallocated objects might do anything. It might work, it might not, it might spill your coffee or start a nuclear war. Don’t do it.
这篇关于为什么我可以将消息发送到NSArray的解除分配的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!