2

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

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

4

4 回答 4

6

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

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

而且您希望在第二行出现分段错误,但实际上并非如此。

原因是运气!

操作系统将捕获对您的进程不拥有的内存的访问,但它不会监管您进程内发生的所有事情。在这种情况下,您正在访问已标记为空闲的内存,但它仍然属于您的进程,因此行为是undefined。内存在几毫秒前是有效的,所以很可能还没有人开始重用这页内存,所以它可能仍然有有效的数据。所以它可能会成功。但它也可能失败。

这是糟糕的代码,你不应该发布它。但仅仅因为它不正确和未定义并不意味着它不起作用。

于 2012-09-11T17:36:26.040 回答
1

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

于 2012-09-11T17:26:36.710 回答
1

在最简单的“概念”情况下,deallocNSObject 的例程执行free操作,镜像例程malloc中的完成alloc。在实践中它可能会有所不同,但这都是雾里看花,只要概念模型得到满足。

如果您[super dealloc]首先将其放入(ARC 之前)dealloc例程中,则它通常不会出现段错误,因为该空间在被释放时没有时间被其他对象覆盖(并且在释放时它不会物理消失-它只是进入一个“可用”列表)。

于 2012-09-11T17:36:52.280 回答
1

是的,alloc是分配完成的地方。请注意,它可能会或可能不会完成,有时根本没有分配(这是一个实现细节)。分配通常发生NSObjectalloc.

如果分配了内存,那么链式调用dealloc就是最终释放它的调用。

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

但是,要记住的重要一点是,除了在 dealloc 实现本身中的调用之外,您永远不应该直接调用。Objective C 是引用计数的。当您完成一个对象时,您不会这样做。取而代之的是你它(或者如果你完成了它,但你将它返回给调用者并且不知道调用者是否会使用它)。当系统确定没有人再引用该对象时,实际调用会自动发生。dealloc[super dealloc]deallocreleaseautoreleasedealloc

编辑:

我会澄清有时根本没有分配。事实上,如果您调用 alloc,分配通常会发生,但 init* 方法可能会撤消它。通常,所有对alloc的调用都应紧跟对其中一个初始化程序的调用。然而,初始化器不需要初始化self它们接收到的。相反,他们可以摆脱它(因此释放内存)并返回一个完全不同的对象,该对象可能已分配也可能未分配。

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

于 2012-09-11T17:41:32.390 回答