【问题标题】:Can an Objective-C object's retain count drop below zero?Objective-C 对象的保留计数可以降到零以下吗?
【发布时间】:2017-02-05 05:07:00
【问题描述】:

我在Objective-C中学习了手动内存管理,每篇文章都说:“当对象的保留计数降至0时,调用dealloc方法并销毁对象”。仅此而已。

但是有几个问题没有答案:我可以将保留计数降低到 0 以下吗?是否可以在对象死亡之前连续多次调用[object release],并导致保留计数降至 0 以下?如果我这样做了,宇宙还会存在吗?

Google 什么也没给我,比如:“你为什么要问这个问题?没人在乎。再去阅读一下内存管理。”

【问题讨论】:

  • 尝试搜索“过度释放目标c”
  • 其实我应该说的是:你尝试的时候发生了什么?您的问题很容易通过实验得到解答。
  • 不,宇宙将不再存在。您将在某处崩溃 BAD_ACCESS。你自己没有试过吗?令人钦佩的是,您正在学习手动内存管理,它将帮助您从内部理解事物。但它非常不安全,在现代项目中不使用。
  • 当前运行时(至少可以追溯到几个版本)永远不会将计数降至零。相反,当它减少到零时,它只是跳过该部分并调用dealloc。查看众多问题,询问为什么 retainCount 报告 1 为 dealloced 对象。

标签: objective-c memory-management release dealloc retaincount


【解决方案1】:

如果在保留计数为1 时调用release,则会立即调用dealloc。所以保留计数甚至不会达到0

进一步调用 release 将导致运行时崩溃,因为您将取消对已释放对象的引用。

所以不,那时宇宙将不存在:)

【讨论】:

  • 请注意,保留计数永远不会下降到零;运行时不会浪费在销毁对象之前递减的周期。
  • 感谢@bbum 提供更多详细信息,我更新了答案!
【解决方案2】:

保留计数可以为 0 或更高,但不能更少。当一个对象被分配堆内存(alloc init)时,保留计数设置为 1。然后您可以通过在其上调用 retain 来增加保留计数(据我所知,次数不受限制,但我可以错了)。

调用 release 只是将保留计数减少 1。然后系统会定期检查对象的保留计数并释放任何计数为 0 的对象。

在已释放的对象上调用release 与在NULL 对象上调用任何方法相同,并且应该简单地返回NULLvoid。但是,如果您明确地管理堆内存,那么您应该非常知道自己在做什么。

一些有趣的点:

为什么保留计数可以超过 1?

这是为了让一个对象在其他东西仍然需要它时不会被释放。例如。假设你有petownervetpet 实例由 owner 实例拥有。 owner 转到vet 实例,vet 也拥有pet 的所有权。在一段时间内pet 有两个所有者,因此(如果retain 已被调用)保留计数为2。假设ownervet 完成@987654341 之前被释放@;如果一切都已正确完成,pet 将不会被释放,它只会通过从owner 调用release 将其保留计数减少到 1。然后vet 可以以pet 结束,调用releasepet 将被释放。

我相信您知道这已全部被自动引用计数所取代。作为开发人员,我们现在必须简单地了解一个对象与另一个对象的关系类型。

因此,如果您现在创建一个对象,它将在它超出范围时被释放除非它与另一个对象有很强的关系(拥有)。您仍然可以获得两个对象彼此之间具有强关系的保持循环,因此永远不符合解除分配的条件。

适用于冗长的答案,但内存管理是应用程序编程的核心部分,非常有趣。

【讨论】:

  • "在已经释放的对象上调用 release 与在 NULL 上调用任何方法相同" 仅当指针实际设置为 nil 时。将release 发送到已释放的对象是程序员错误:未定义的行为。
  • 这个答案一开始就非常错误。保留计数可以永远不会为 0。系统定期检查任何内容。在已释放对象上调用方法是未定义的行为,并且会经常崩溃,它根本没有就像在 NULL 上调用任何方法一样。 vet/owner/pet 的类比是正确的。
猜你喜欢
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多