为了账号安全,请及时绑定邮箱和手机立即绑定

呼叫-retainCount被认为是有害的

/ 猿问

呼叫-retainCount被认为是有害的

慕的地6264312 2019-08-19 15:29:47

呼叫-retainCount被认为是有害的

或者,为什么retainCount我的暑假没有使用

这篇文章旨在征求关于该臭名昭着的方法的原因和原因的详细报道retainCount,以巩固围绕SO的相关信息。*

  1. 基础知识:不使用的官方理由是什么retainCount?是否有过任何情况下当它可能是有用的?应该做些什么?**随意编辑。

  2. 历史/解释:如果不打算使用Apple,为什么Apple在NSObject协议中提供此方法?Apple的代码是否依赖于retainCount某些目的?如果是这样,为什么不把它隐藏在某个地方?

  3. 为了更深入地理解:对象可能具有与用户代码假设不同的保留计数的原因是什么?您能否举例说明框架代码可能会使用哪些标准程序导致这种差异?是否有任何已知的情况,保留计数总是与新用户可能期望的不同?

  4. 你认为还有什么值得关注的retainCount吗?


*不熟悉Objective-C和Cocoa的编码人员经常努力解决或至少误解参考计数方案。教程解释可能提及保留计数,这(根据这些解释)当你打电话上去一个retainalloccopy由一个当你调用等,向下release(并在当你调用未来的某一时刻autorelease)。

因此,一个崭露头角的可可黑客克里斯可以很容易地认识到,检查一个对象的保留计数对于解决一些内存问题是有用的,而且,有一种方法可用于每个被调用的对象retainCount!克里斯打电话retainCount给几个对象,这个对象太高了,一个太低了,到底发生了什么?!因此,Kris在SO上发帖,“我的记忆管理出了什么问题?” 然后一群<bold>,<large>字母下降说“不要那样做!你不能依靠结果。”,这是好的,但我们的强悍编码器可能需要更深入的解释。

我希望这会变成一个常见问题解答,一个很好的信息论文/讲座的页面,我们的任何专家都倾向于写一个,当他们想知道时可以指出新的可可头retainCount

**我不想让它过于宽泛,但是经验或有关验证/调试保留和释放配对的文档的具体提示可能适合此处。

***在虚拟代码中; 很明显,一般公众无法访问Apple的实际代码。


查看完整描述

2 回答

?
holdtom

基础知识:不使用retainCount的官方原因是什么?

自动释放管理是最明显的 - 您无法确定retainCount在本地或外部(在辅助线程或另一个线程的本地池中)自动释放池中有多少引用。

此外,有些人在泄漏方面存在问题,并且在更高级别引用计数以及自动释放池如何在基本级别上工作。他们会编写一个程序而没有(太多)考虑正确的引用计数,或者没有正确学习引用计数。这使得他们的程序很难调试,测试和改进 - 这也是一个非常耗时的整改。

阻止其使用(在客户端级别)的原因有两个:

1)该值可能因多种原因而有所不同。仅仅是线程就足以让人永不信任它。

2)您仍然必须实现正确的引用计数。retainCount永远不会让你免于不平衡的引用计数。

什么时候有可能有用吗?

可以在实际上使用它以一种有意义的方式,如果你写你自己的分配器或引用计数方案,或者如果你的对象住在一个线程,你有机会访问的任何所有的自动释放池,它能够在存在的。这也意味着你不会与任何外部API共享。模拟这个的简单方法是创建一个包含一个线程,零自动释放池的程序,并按照“正常”方式进行引用计数。您不太可能需要解决此问题/将此程序编写为“学术”原因之外的任何其他内容。

作为调试辅助工具:您可以使用它来验证保留计数是否异常高。如果采用这种方法,请注意实现差异(本文中引用了一些差异),并且不依赖它。甚至不将测试提交到SCM存储库。

在极少数情况下,这可能是一种有用的诊断方法。它可以用来检测:

  • 过度保留:如果您的程序可以达到分配,则保留计数中存在正不平衡的分配不会显示为泄漏。

  • 许多其他对象引用的对象:此问题的一个例子是在多线程上下文中操作的(可变的)共享资源或集合 - 频繁访问或更改此资源/集合可能会在程序的执行中引入重大瓶颈。

  • 自动释放水平:自动释放,自动释放池和保留/自动释放循环都需要付出代价。如果您需要最小化或减少内存使用和/或增长,您可以使用此方法来检测过多的情况。

从Bavarious的评论(下面):高值也可能表示无效的分配(dealloc'd实例)。这完全是一个实现细节,同样不能在生产代码中使用。在启用僵尸时,传递此分配将导致错误。

应该做什么呢?

如果您不负责返回内存self(也就是说,您没有编写分配器),请不要管它 - 这是没用的。

你必须学习正确的引用计数。

为了更好地理解发布和自动释放的使用,设置一些断点并了解它们的使用方式,在什么情况下等等。您仍然需要学会正确使用引用计数,但这可以帮助您理解为什么它没用。

更简单:使用Instruments跟踪alloc和ref计数,然后分析活动程序中几个对象的引用计数和callstack。

历史/解释:如果不打算使用Apple,为什么Apple会在NSObject协议中提供此方法?Apple的代码是否出于某种目的依赖retainCount?如果是这样,为什么不把它隐藏在某个地方?

我们可以假设它是公开的,主要有两个原因:

1)在托管环境中适当的引用计数。这对分配器来说很好用retainCount- 真的。这是一个非常简单的概念。当-[NSObject release]被调用时,裁判计数器(除非被覆盖)可以被调用,并且该对象可以如果被释放retainCount为0(调用的dealloc之后)。这在分配器级别都很好。分配器和区域(很大程度上)是抽象的......这使得结果对普通客户来说毫无意义。有关为什么retainCount在客户端级别不能等于0,对象释放,释放序列等的详细信息,请参阅bbum(下面)的注释。

2)使其可用于需要自定义行为的子类,以及其他引用计数方法是公共的。它在某些情况下可能很方便,但它通常用于错误的原因(例如不朽的单身人士)。如果您需要自己的参考计数方案,那么这个家庭可能值得重写。

为了更深入地理解:对象可能具有与用户代码假设不同的保留计数的原因是什么?您能否举例说明框架代码可能会使用哪些标准程序导致这种差异?是否有任何已知的情况,保留计数总是与新用户可能期望的不同?

同样,自定义引用计数方案和不朽对象。NSCFString文字属于后一类:

NSLog(@"%qu", [@"MyString" retainCount]); // Logs: 1152921504606846975

你认为还有什么值得一提的关于retainCount吗?

它作为调试辅助工具毫无用处。了解如何使用泄漏和僵尸分析,并经常使用它们-即使以后你有引用计数的句柄。


更新: bbum最近发布了一篇名为retainCount的文章是没用的。本文详细讨论了为什么-retainCount在绝大多数情况下没有用处。


查看完整回答
反对 回复 2019-08-19
?
catspeake

一般的经验法则是,如果你使用这种方法,你最好确定你知道你在做什么。如果您正在使用它来调试内存泄漏,那么您做错了,如果您正在查看对象发生了什么,那么您做错了。

有一种情况我使用它,发现它很有用。这是在做一个共享对象缓存,我想在没有任何引用它的情况下刷新对象。在这种情况下,我一直等到retainCount等于1,然后我知道没有其他任何内容可以释放它,这显然在垃圾收集环境中无法正常工作,并且有更好的方法来实现它。但这仍然是我见过的唯一“有效”用例,并不是很多人会做的事情。


查看完整回答
反对 回复 2019-08-19

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信