Objective-C:将自动释放的对象设置为nil

3

将一个自动释放的对象设置为nil是否安全?我知道我不需要释放一个自动释放的对象,但如果我想要立即释放对象以最小化内存使用,我可以将对象设置为nil吗?

我可能在一段时间前读过这个问题,但我不记得在哪里看到的,我想确保这样做是安全的。


1
将一个自动释放的对象设置为nil是安全的,在某些情况下,它可以通过代码来显示你的意图。然而,将对象设置为nil并不会立即释放它。它只有在自动释放池被清空时才会被释放。 - Jason Coco
这是在处理非常内存密集型的处理时理解内存管理非常重要的概念。有很多Objective-C文献没有澄清这一点,我认为很多开发人员可能会将ARC与像Java这样的传统垃圾收集模型混淆。我很高兴验证我的理解是正确的,因为即使是我自己也曾经对此产生过疑问。 - Joey Carson
2个回答

15

我认为你错过了一些非常基本的东西。将对象设置为nil对内存管理没有任何帮助。这里是发生的事情:alt text http://gallery.me.com/davedelong/100084/Pointers1/web.png?ver=12783505480001

在这个图像中,您有堆栈(其中包含本地变量;它更或多或少等同于您在执行代码时所处的位置)。如果您声明类似int bar = 42;的内容,则bar位于堆栈上。右侧是堆。这是属于您的应用程序的全局内存空间。堆是为解决作用域问题而发明的:如何使有用的信息存在当前函数(或方法)的范围之外。当我们malloc空间时,我们被分配一个在堆上的内存槽。当您alloc/init一个对象时,该对象位于堆上。在Objective-C中,所有对象都位于堆上。*因此,让我们考虑这行代码:

MyObject * foo = [[MyObject alloc] init];

我们有两件事情要做。首先,我们已经在堆上分配了一个足够大的空间来容纳一个MyObject结构体。然后,我们把那块内存的位置赋值给一个叫做foo的局部变量。在上面的图片中,左边的红色圆圈是foo,右边的红色斑点是实际的MyObject(以及它的所有数据)。到目前为止还清楚吗?
这是当你"将一个对象设置为nil"(foo = nil;)时会发生的事情。 alt text http://gallery.me.com/davedelong/100084/Pointers2/web.png?ver=12783505490001 你会看到对象仍然存在于堆上。实际上唯一改变的是你的局部变量foo不再指向堆上的内存块。它指向0nilNULL,无论你想怎么称呼它),这就是我们表示"这不再指向任何相关的东西"的方法。
简而言之,将变量设置为nil与内存管理无关。如果您想立即摆脱一个对象,那么请使用release而不是autorelease。但即使如此,这也不能保证“立即销毁”,因为其他东西可能会retain该对象(这正是使用保留释放内存管理模型的全部意义)。
此外,一旦您完成了一个对象(并在调用release或autorelease之后),将变量设置为nil仍然是一个好习惯,以避免潜在的问题。在Objective-C中,我们可以安全地发送消息到nil,而不像Java那样会出现问题。但是,如果您没有将变量设置为"nil",则可能会发生糟糕的事情。假设foo指向一个MyObject实例,然后销毁了MyObject实例(您已经将其解除引用,但未将其设置为nil)。如果您再次尝试在foo上调用方法,则应用程序将崩溃。如果将foo设置为"nil",则应用程序将继续进行下去。它可能不会执行您所希望的操作,但这是完全不同的问题。
欢迎来到Objective-C内存管理的奇妙世界。

* 除了本地块,但只限于复制前。还有一些其他注意事项,但那已经涉及到奥秘了。


1
加上插图,提高了一些水平啊。赞一个。 - bbum
@bbum 我喜欢 Omnigraffle。我也发现仅用文字来解释堆栈和堆往往会让人感到困惑。(至少对我来说是这样:当我能够将其可视化时,一切都变得清晰了) - Dave DeLong
我希望这些图片现在不是404错误(因为mobileMe已经关闭)。我是一个视觉学习者!:) 无论如何,非常棒的答案,已点赞! - taber
@taber 当时,我丢失了原始文件。 - Dave DeLong

0

是的,这是一个好的实践,因为它表明对象未被使用 - 即没有引用数据。

值得一提的是,你也会在苹果的示例代码中看到它。


听起来你把垃圾收集器和自动释放池混淆了。在GC环境中,将本应持久存在的对象引用设置为nil是有益的。但即使在Mac上,GC也经常不被使用,在iOS上也不可用。仍然可能有设置nil的潜在好处,例如确保没有过时的指针留下来陷阱不谨慎的编码人员,但它不会影响内存管理。 - walkytalky
@walkytalky同意。我从来没有提到过GC。我只是提到这是一个好的实践。出于你提到的相同原因——保证清洁。 - Jason McCreary
好的。但在这种情况下,很难看出短语“它让内存池知道它未使用 - 即没有引用数据”的含义是什么。 - walkytalky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接