为什么我可以将消息发送到NSArray的解除分配的实例? [英] Why can I send messages to a deallocated instance of NSArray?

查看:68
本文介绍了为什么我可以将消息发送到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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆