调用-retainCount被视为有害 [英] Calling -retainCount Considered Harmful

查看:104
本文介绍了调用-retainCount被视为有害的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

或者,为什么我未使用 retainCount 在我的暑假



这篇文章旨在征求关于臭名昭着方法 retainCount 的详细记录,以便整合SO周围浮动的相关信息。 p>


  1. 基本信息:不使用 retainCount 的官方原因是什么?是否有任何情况 当它可能是有用的?应该做什么?**随意编辑。


  2. 历史/解释:Apple为什么在 NSObject 协议(如果不是)打算使用? Apple的代码是否依赖于 retainCount 用于某些目的?如果是,为什么不隐藏在某处?


  3. 为了更深入的理解:一个对象可能有不同的保留计数,假设从用户代码?你能给出任何框架代码可能使用的标准过程的示例***引起这样的差异吗?是否有任何已知的情况,其中保留计数始终与新用户可能期望的不同?


  4. 值得关注 retainCount







*
对于Objective-C来说是新手的人,Cocoa经常纠正或者至少误解引用计数方案。当你调用 retain alloc 时,教程解释可能会提到保留计数,根据这些解释, , copy 等,当你调用 release 调用 autorelease )。



一个萌芽的可可黑客Kris得到一个想法,检查对象的保留计数将有助于解决一些内存问题,并且看,有一个方法可用在每个对象 retainCount ! Kris在几个对象上调用 retainCount ,这个太高了,太低了,发生了什么事?所以Kris发表了一篇文章,我的内存管理有什么问题?然后生成< bold>,< large>字母下降说不要这样做,你不能依赖结果,这是好的,但我们的强大的编码器可能需要更深入的解释。


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



**我不想让这个太宽泛,但是从经验或文档的具体提示验证/调试保留和释放配对可能适合这里。



***在虚拟代码中;显然一般公众不能访问苹果的实际代码。

解决方案


基本信息:不使用retainCount的正式理由是什么?


自动释放管理是最明显的 - 你没有办法确保由 retainCount 表示的引用中有多少在本地或外部(在辅助线程或在另一线程的本地池中)自动释放池。



另外,有些人有泄漏的麻烦,在更高级别的引用计数和自动释放池如何工作在基本水平。他们将写一个程序没有(很多)考虑正确的引用计数,或没有学习ref计数正确。这使得他们的程序很难调试,测试和改进 - 它也是一个非常耗时的整改。



阻止其使用的原因(在客户端级别)是双重的:



1)值可能因为这么多原因而有所不同。 单独的线程是足够信任它的原因。



2)您仍然需要实现正确的引用计数。 retainCount 永远不会从不平衡的引用计数中救出您。


是否有任何情况,它可能是有用的?


你可以 如果您写了自己的分配器或引用计数方案,或者您的对象存在于一个线程,并且您可以访问它可能存在的任何所有自动释放池,那么它将以有意义的方式。这也意味着您不会与任何外部API共享。模拟这个的简单方法是创建一个程序与一个线程,零自动释放池,并做你的引用计数正常的方式。这不太可能是你需要解决这个问题/写这个程序为任何非学术的原因。



作为一个调试助手:你可以使用它来验证保留计数是否异常高。如果你采取这种方法,注意实现差异(一些在这篇文章中引用),不要依赖它。甚至不要将测试提交到您的SCM存储库。



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




  • 过度保留:保留计数不正确的分配不会显示为


  • 许多其他对象引用的对象:这个问题的一个例子是一个(mutable)共享资源或集合在多线程环境中运行 - 频繁访问或对此资源/集合的更改可能会在程序执行中引入严重的瓶颈。


  • 自动发布级别:自动释放,自动释放池和保留/自动释放循环都有成本。如果您需要最小化或减少内存使用和/或增长,您可以使用此方法检测过多的病例。




从与Bavarious的评论(下面):一个高值也可能表示无效的分配(dealloc'd实例)。这完全是一个实现细节,并且在生产代码中不可用。


应该怎么办?


如果你不负责返回 self 的内存(即你没有写一个分配器)



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



理解释放和自动释放使用,设置一些断点并了解它们的使用方式,在什么情况下等等。你仍然需要学习使用引用计数正确,但这可以帮助你理解为什么它是无用的。 p>

更简单:使用Instruments来跟踪分配和引用计数,然后分析活动程序中多个对象的引用计数和调用堆栈。


历史/解释:为什么苹果在NSObject协议中提供这种方法,如果不打算使用? Apple的代码是否依赖于retainCount用于某些目的?


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



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



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


为了更深入的理解:可能有不同于用户代码假设的保留计数?你能给出任何框架代码可能使用的标准过程的示例***引起这样的差异吗?是否存在任何已知的情况,其中保留计数总是不同于新用户可能期望的计数。


和不朽的对象。 NSCFString 文字属于后一类:

  NSLog qu,[@MyStringretainCount]); 
// Logs:1152921504606846975




值得一提的是retainCount?


它没有用作调试助手。学习使用泄漏和僵尸分析,并经常使用它们,即使

有引用计数的处理。






更新: bbum最近发布了一篇题为 retainCount是无用的。该文章详细讨论了为什么 -retainCount 在绝大多数情况下不起作用。


Or, Why I Didn't Use retainCount On My Summer Vacation

This post is intended to solicit detailed write-ups about the whys and wherefores of that infamous method, retainCount, in order to consolidate the relevant information floating around SO.*

  1. The basics: What are the official reasons to not use retainCount? Is there ever any situation at all when it might be useful? What should be done instead?** Feel free to editorialize.

  2. Historical/explanatory: Why does Apple provide this method in the NSObject protocol if it's not intended to be used? Does Apple's code rely on retainCount for some purpose? If so, why isn't it hidden away somewhere?

  3. For deeper understanding: What are the reasons that an object may have a different retain count than would be assumed from user code? Can you give any examples*** of standard procedures that framework code might use which cause such a difference? Are there any known cases where the retain count is always different than what a new user might expect?

  4. Anything else you think is worth metioning about retainCount?


* Coders who are new to Objective-C and Cocoa often grapple with, or at least misunderstand, the reference-counting scheme. Tutorial explanations may mention retain counts, which (according to these explanations) go up by one when you call retain, alloc, copy, etc., and down by one when you call release (and at some point in the future when you call autorelease).

A budding Cocoa hacker, Kris, could thus quite easily get the idea that checking an object's retain count would be useful in resolving some memory issues, and, lo and behold, there's a method available on every object called retainCount! Kris calls retainCount on a couple of objects, and this one is too high, and that one's too low, and what the heck is going on?! So Kris makes a post on SO, "What's wrong with my memory management?" and then a swarm of <bold>, <large> letters descend saying "Don't do that! You can't rely on the results.", which is well and good, but our intrepid coder may want a deeper explanation.

I'm hoping that this will turn into an FAQ, a page of good informational essays/lectures from any of our experts who are inclined to write one, that new Cocoa-heads can be pointed to when they wonder about retainCount.

** I don't want to make this too broad, but specific tips from experience or the docs on verifying/debugging retain and release pairings may be appropriate here.

***In dummy code; obviously the general public don't have access to Apple's actual code.

解决方案

The basics: What are the official reasons to not use retainCount?

Autorelease management is the most obvious -- you have no way to be sure how many of the references represented by the retainCount are in a local or external (on a secondary thread, or in another thread's local pool) autorelease pool.

Also, some people have trouble with leaks, and at a higher level reference counting and how autorelease pools work at fundamental levels. They will write a program without (much) regard to proper reference counting, or without learning ref counting properly. This makes their program very difficult to debug, test, and improve -- it's also a very time consuming rectification.

The reason for discouraging its use (at the client level) is twofold:

1) The value may vary for so many reasons. Threading alone is reason enough to never trust it.

2) You still have to implement correct reference counting. retainCount will never save you from imbalanced reference counting.

Is there ever any situation at all when it might be useful?

You could in fact use it in a meaningful way if you wrote your own allocators or reference counting scheme, or if your object lived on one thread and you had access to any and all autorelease pools it could exist in. This also implies you would not share it with any external APIs. The easy way to simulate this is to create a program with one thread, zero autorelease pools, and do your reference counting the 'normal' way. It's unlikely that you'll ever need to solve this problem/write this program for anything other than "academic" reasons.

As a debugging aid: you could use it to verify that the retain count is not unusually high. If you take this approach, be mindful of the implementation variances (some are cited in this post), and don't rely on it. Don't even commit the tests to your SCM repository.

This may be a useful diagnostic in extremely rare circumstances. It can be used to detect:

  • Over-retaining: An allocation with a positive imbalance in retain count would not show up as a leak if the allocation is reachable by your program.

  • An object which is referenced by many other objects: One illustration of this problem is a (mutable) shared resource or collection which operates in a multithreaded context - frequent access or changes to this resource/collection can introduce a significant bottleneck in your program's execution.

  • Autorelease levels: Autoreleasing, autorelease pools, and retain/autorelease cycles all come with a cost. If you need to minimize or reduce memory use and/or growth, you could use this approach to detect excessive cases.

From commentary with Bavarious (below): a high value may also indicate an invalidated allocation (dealloc'd instance). This is completely an implementation detail, and again, not usable in production code. Messaging this allocation would result in a error when zombies are enabled.

What should be done instead?

If you're not responsible for returning the memory at self (that is, you did not write an allocator), leave it alone - it is useless.

You have to learn proper reference counting.

For a better understanding of release and autorelease usage, set up some breakpoints and understand how they are used, in what cases, etc. You'll still have to learn to use reference counting correctly, but this can aid your understanding of why it's useless.

Even simpler: use Instruments to track allocs and ref counts, then analyze the ref counting and callstacks of several objects in an active program.

Historical/explanatory: Why does Apple provide this method in the NSObject protocol if it's not intended to be used? Does Apple's code rely on retainCount for some purpose? If so, why isn't it hidden away somewhere?

We can assume that it is public for two primary reasons:

1) Reference counting proper in managed environments. It's fine for the allocators to use retainCount -- really. It's a very simple concept. When -[NSObject release] is called, the ref counter (unless overridden) may be called, and the object can be deallocated if retainCount is 0 (after calling dealloc). This is all fine at the allocator level. Allocators and zones are (largely) abstracted so... this makes the result meaningless for ordinary clients. See commentary with bbum (below) for details on why retainCount cannot be equal to 0 at the client level, object deallocation, deallocation sequences, and more.

2) To make it available to subclassers who want a custom behavior, and because the other reference counting methods are public. It may be handy in a few cases, but it's typically used for the wrong reasons (e.g. immortal singletons). If you need your own reference counting scheme, then this family may be worth overriding.

For deeper understanding: What are the reasons that an object may have a different retain count than would be assumed from user code? Can you give any examples*** of standard procedures that framework code might use which cause such a difference? Are there any known cases where the retain count is always different than what a new user might expect?

Again, a custom reference counting schemes and immortal objects. NSCFString literals fall into the latter category:

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

Anything else you think is worth mentioning about retainCount?

It's useless as a debugging aid. Learn to use leak and zombie analyses, and use them often -- even after you have a handle on reference counting.


Update: bbum has recently posted an article entitled retainCount is useless. The article contains a thorough discussion of why -retainCount isn’t useful in the vast majority of cases.

这篇关于调用-retainCount被视为有害的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆