我一直在寻找通过询问StackOverflow上的问题,但有这么多有关Objective-C的内存管理,我无法找到我一直在寻找的答案。
现在的问题是,如果它是确定(和recommnded)将新创建的对象的集合(比如NSMutableArray的)之前调用自动释放? 或者我应该将它添加后明确地释放它。 (我知道的NSMutableArray预订购保留的对象)
这说明我的问题:
方案A(自动释放):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
方案B(显式发布):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
我认为都是正确的,但我不知道,我肯定不知道的方式参访什么。
Objective-C的大师能提供一些线索对此有何看法?
两者都是正确的,因为你是他们期待将工作。
我个人更喜欢使用后一种方法,但只是因为我喜欢明确的关于对象时得到释放。 通过自动释放的对象,所有我们正在做的是说“这个对象将在未来的某个任意点获得释放。” 这意味着你可以把自动释放对象放入数组,破坏了数组和对象可能(可能)仍然存在。
对于后者的方法,对象会得到立即与阵列(提供没有其他已出现并保留其在此期间)被破坏。 如果我在一个内存受限的环境中(比如,iPhone的),我需要小心我使用多少内存,我会用后一种方法只是让我没有那么多的物体在缠绵一个NSAutoreleasePool地方。 如果内存使用是不是你一个大问题(它通常是不适合我,要么),那么无论方法完全可以接受的。
恕我直言,这方法是“正确”是偏好的问题。 我不同意谁主张不使用应答不同意autorelease
,但我的选择是使用autorelease
,除非有一个压倒性的令人信服的理由不这样做。 我会列出我的理由,你可以决定是否他们不适合您的编程风格。
正如查克指出,有一个半城市传说有某种开销使用自动释放池。 这不能从事实并非如此,这来自使用Shark.app挤压性能的最后一位出来的代码花了无数时间。 试图优化,这是在为“过早优化”领土深。 如果,且仅当,Shark.app为您提供了确凿的数据,这可能是一个问题,你应该甚至考虑在寻找它。
正如其他人所指出的,一个自动释放的对象“发布在以后的某个点”。 这意味着他们萦绕,占用内存,直到“后点”来临时。 对于“最”的情况下,这是一个事件处理经过底部的运行循环休眠,直到下一个事件(定时器,用户点击的东西,等等)前。
偶尔,不过,你需要摆脱那些临时对象的时间越早,而不是以后。 例如,你需要处理一个庞大的,多兆字节的文件,或行数以万计的从数据库。 发生这种情况时,你需要放置一个NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
在精心选择的点,然后是[pool release];
在底部。 这几乎总是发生在某种“循环批处理”的,所以它在一些重要的循环的开始和底部通常是。 同样,这应该基于证据,而不是基于预感。 Instrument.app的是ObjectAlloc中使用发现这些问题点什么。
为什么我喜欢的主要原因autorelease
到release
,虽然是,它是写无泄漏的程序容易得多。 总之,如果你选择去的release
路线,你需要确保 release
被最终被送到了obj
,在情况下。 虽然这看起来像它可能很简单,它实际上是很难令人惊讶的在实践中做到。 把你的例子,比如:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
现在想象一下,由于某种原因,东西,地方,巧妙地侵犯了您的假设array
是可变的,也许会使用一些方法来处理结果的结果,以及含有处理结果返回阵列作为创建NSArray
。 当您发送addObject:
以不可变NSArray
,一个会抛出异常,你将永远不会发送obj
其release
的消息。 或者,也许不顺心的事时,地方之间obj
是alloc
d和所需的呼叫release
,就像你检查一些条件和return()
立即错误,因为它滑落你记住,呼吁release
以后必须发生。
你刚刚泄露的对象。 大概自己签订长达数天的努力找出为什么它是你泄露了。 从以往的经验,你会花很多时间看一下上面的代码,相信它不可能是泄漏的来源,因为你很清楚发送obj
一个release
。 又过了几天,你会体验到,你就开悟了问题的原因是什么,只能说是一个宗教的顿悟。
考虑autorelease
的情况下:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
现在,它不再是问题,会发生什么,因为它几乎是不可能泄露obj
意外,即使在极不寻常的或特殊的角落案件。
他们都是正确的,但B可以首选,因为它没有任何开销。 自动释放将导致自动释放池,负责的对象。 这有它,当然,得到所涉及的对象的数量乘以一个非常小的开销。
因此,与一个对象A和B都或多或少相同,但绝对不会在方案中使用一个具有大量的对象添加到阵列。
在不同的情况自动释放可能会延迟,并在线程结束积累许多对象的释放。 这可能是次优的。 要小心,反正自动释放发生了很多没有明确的干预。 例如,许多干将都以这种方式实现:
return [[myObject retain] autorelease];
所以每当你打电话,吸气,你的对象添加到自动释放池。
您可以将autorelease
的任何一点消息,因为它没有采取行动,直到应用程序的消息循环重复(即,直到所有的方法都完成了响应用户输入执行)。
http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text
你有alloc
“编的对象,那么你的工作在某些时候将其释放。 这两个代码段的工作仅仅是相同的,正确的方法,用autorelease
方式作为potentionally慢对口。
个人来说,我更喜欢autorelease
方式,因为它只是更容易输入,几乎从来都是一个瓶颈。
他们都OK。 有些人会告诉你,以避免因“开销”或一些这样的东西自动释放,但事实是,几乎没有任何开销。 来吧,基准,并设法找到“开销”。 你会避免它的唯一原因是在像iPhone上的内存匮乏的局面。 在OS X,你实际上是无限的内存,因此它不会产生太大的差别。 只需使用取其您最方便的。
我更喜欢A(自动释放)为了简洁和“安全”,因为强尼调用它。 它简化了我的代码,我从来没有遇到与它的问题。
也就是说,直到今天:我有一个问题,它添加到阵列之前自动释放块。 看到我的计算器问题: [myArray的ADDOBJECT:[objcBlock复制]自动释放]上dealloc'ing阵列崩溃 (更新:原来,问题是在我的代码的其他地方,不过,有与自动释放行为细微的差别... )