为什么我可以在没有segfaulting的[super dealloc]之后发布一个ivar?

时间:2012-09-11 17:22:31

标签: objective-c cocoa memory-management dealloc

似乎在Objective-C中,负责内存分配的方法(如C中的malloc())是-[NSObject alloc]。那释放那些记忆怎么样?这是由-[NSObject dealloc]完成的吗?这就是为什么在我们自己的班级dealloc中,我们必须最后拨打[super dealloc]而不是第一个?

我问,因为我不明白为什么,如果我先放[super dealloc],然后在下一行使用[_bar release]释放一个对象,我就不会出现分段错误。运行[super dealloc]后,如果它释放了对象的内存,_bar应该已经是一个不属于该进程的内存块。

4 个答案:

答案 0 :(得分:6)

我想你是说,你有这个代码:

- (void)dealloc
{
    [super dealloc];
    [_bar release]; // _bar is a member variable
}

你希望在第二行得到分段错误,但实际上你不是。

原因就是运气!

操作系统会捕获对您的进程不拥有的内存的访问权限,但它不会监控进程内发生的所有事情。在这种情况下,您正在访问已标记为可用的内存,但它仍属于您的进程,因此行为未定义。内存在几毫秒之前就有效了,所以很可能没有人开始重用这个内存页面,因此它可能仍然有有效的数据。所以它可能会成功。但它也可能失败。

这是错误的代码,您不应该发货。但仅仅因为它不正确并且未定义并不意味着它不起作用。

答案 1 :(得分:1)

-dealloc最终释放与Objective-C对象相关联的内存(可能是通过free(),但这是一个实现细节。)您之后能够发送消息的唯一原因-dealloc是因为未定义的行为。发送[super dealloc]后,发送给self或其ivars的任何其他邮件都不安全。

答案 2 :(得分:1)

在最简单的“概念”情况下,NSObject的dealloc例程执行free操作,镜像malloc例程中的alloc。在实践中它可能是不同的,但只要概念模型得到满足,那就是所有的烟雾和镜子。

如果你把[super dealloc]放在你的(pre-ARC)dealloc例程中,它通常不会出错,因为空间虽然被释放,但没有时间被其他对象覆盖(并且在解除分配时它不会消失 - 它只会进入“可用”列表)。

答案 3 :(得分:1)

是的,alloc是分配完成的地方。请注意,它可能会也可能不会完成,有时根本没有分配(这是一个实现细节)。分配通常发生在NSObject的{​​{1}}实施中。

如果分配内存,则对alloc的链式调用最终会释放它。

调用dealloc后,您不应该访问实例变量。这并不意味着,如果你这样做,你会得到一个段错误。您可能会或可能不会发生段错误,这是未定义的行为。

重要的是要记住,除了在dealloc实现本身中调用[super dealloc]之外,你应该永远直接调用dealloc。目标C是参考计数。完成对象后,不要[super dealloc]它。相反,你dealloc它(或者release如果你已经完成它但是你将它返回给调用者并且不知道调用者是否会使用它。当系统确定没有人会再引用该对象时,对autorelease的实际调用会自动发生。

编辑:

我会澄清有时根本没有分配。实际上,如果调用alloc,通常会发生分配,但init *方法可能会撤消它。通常,对dealloc的所有调用都应立即调用其中一个初始值设定项。但是,初始值设定项不需要初始化它们收到的alloc。他们可以改为摆脱它(因此释放内存)并返回一个完全不同的对象,可能会或可能不会被分配。

因此,在这种情况下,由self分配的内存实际上是由初始化程序释放的(可能会也可能不会调用alloc来执行此操作)。和初始化后得到的对象可能是一个静态对象,它没有在堆上分配,永远不会被释放。它也可以是非指针(无效地址),转换为dealloc(又名(void*))并返回。