你对Objective-C中遍历保留计数并在每次遍历时调用release的代码有何看法?

8

我还在努力理解我找到的一个项目中的这段代码,创建它的人在我问之前已经离开了公司。

以下是代码:

-(void)releaseMySelf{
    for (int i=myRetainCount; i>1; i--) {
        [self release];
    }
    [self autorelease];
}

据我所知,在Objective-C的内存管理模型中,第一个规则是分配另一个对象的对象也负责在未来释放它。这就是我不理解这段代码意义的原因。有意义吗?

20
毫不意外他离开了公司。像那样的代码肯定表明他超出了自身能力范围,没有理解如何编写应用程序的方法,也没有机会学习正确的方式。如果我在一个项目中发现了这样的代码(事实上我曾经运营过一家给有问题项目提供“清理工作”的咨询服务公司),我会立即发出警告并要求检查该人编写的每一行代码。(此外,看起来他正在维护一个与对象的实际保留计数分离的保留计数……这是两个警告信号。) - bbum
9
我想知道是谁写的,这样我就可以确定永远不会和他一起工作。 - Dave DeLong
1
哎呀。我刚刚噎到了。 - Mike C.
1
@uliwitness 嗯,不行。无论 myRetainCount 做什么,这都不可以。 - Jonathan Sterling
1
如果他正在实现自己的引用计数系统,基于系统的RC,则这可能是有效的代码,尽管它还需要某种解决方案,如零化释放时弱引用,以使其正确。最多只能算是一个坏的轮子重新发明。 - bbum
显示剩余2条评论
4个回答

17

作者试图绕过不理解内存管理的问题。他假设一个对象有一个保留计数,每个保留都会增加,因此尝试通过调用相应数量的释放来减少它。也许他没有实现你的理解中的“还要负责在未来释放它”的部分。

然而,在这里查看很多答案,例如 这里 这里以及 这里

请阅读苹果公司的内存管理概念

第一个链接包括一个引用苹果公司的话:

retainCount方法不考虑发送给接收器的任何挂起自动释放消息。

重要提示: 此方法通常对调试内存管理问题没有价值。因为任何数量的框架对象可能已经保留了一个对象以保持对它的引用,同时自动释放池可能正在保持对一个对象的任意数量的延迟释放,所以你很难从这个方法中获得有用的信息。要了解必须遵守的内存管理基本规则,请阅读“内存管理规则”。要诊断内存管理问题,请使用适当的工具:LLVM/Clang静态分析器通常可以在运行程序之前发现内存管理问题。Instruments应用程序中的Object Alloc仪器(请参阅Instruments用户指南)可以跟踪对象分配和销毁。Shark(请参阅Shark用户指南)还可以分析内存分配(以及您的程序的众多其他方面)。


3
顺便提一句,我建议你删除这段代码,并将你的代码运行通过静态分析器。它应该会显示哪些对象应该被释放。 - Eimantas

7

由于所有答案似乎都误将 myRetainCount 解读为 [self retainCount],所以让我来解释一下为什么会有人编写这段代码:可能是因为这段代码在某种程度上会生成线程或以其他方式使客户端向其注册,而myRetainCount有效地是这些客户端的数量,从实际操作系统保留计数中分开,但每个客户端可能也会获得自己的 ObjC风格的 retain。

因此,在请求被中止的情况下可能会调用此函数,并且可以立即处理所有客户端,然后执行所有释放操作。 这不是一个好的设计,但是如果代码就是这样工作的(并且您没有漏掉 int myRetainCount = [self retainCount] 或 retain/release 的覆盖),那至少它并不一定是有缺陷的。

然而,这很可能是职责分配不当或笨拙的尝试,旨在避免保留循环,而实际上并没有真正改进任何东西。


然而,这仍不是正确实现的方法 - 作者仍未正确掌握内存管理 - retain/release 等与线程一起运作。 - mmmmmm
线程只是一个客户端的例子,通常用于注册/注销,例如线程池或“取消所有”行为。 - uliwitness

3

这是一种强制释放内存的不良方法:如果你的程序其余部分编写正确,你永远不需要做任何类似的事情。通常情况下,你的保留和释放是平衡的,因此你永远不需要查看保留计数。这段代码的含义是:“我不知道谁保留了我却忘记释放,我只想释放我的内存;我不在乎其他引用从现在开始会变为悬空引用。”这不会与ARC编译(奇怪的是,转换到ARC可能会解决作者试图解决的错误)。


2
代码的意思是强制对象立即释放,无论未来后果如何。(而且会有后果!)
该代码存在致命缺陷,因为它没有考虑到其他人实际上“拥有”该对象。换句话说,某些东西“分配”了该对象,并且任意数量的其他事物可能已经“保留”了该对象(也许是像NSArray这样的数据结构,也许是自动释放池,也许是一些堆栈帧上的代码只是执行“保留”);所有这些事情都共享对该对象的所有权。如果对象自杀(这就是releaseMySelf所做的),这些“所有者”突然指向错误的内存,这将导致意外行为。
希望像这样编写的代码只会崩溃。也许原始作者通过在其他地方泄漏内存来避免这些崩溃。

1
非常感谢大家!我认为这是一段糟糕的代码。 - Ricardo

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