NSAutoreleasePool自动释放池如何工作?
据我了解,使用alloc,new或者copy创建的任何内容都需要手动释放。例如:
int main(void) { NSString *string; string = [[NSString alloc] init]; /* use the string */ [string release]; }
我的问题是,这样难道不是同样有效吗?:
int main(void) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ [pool drain]; }
解决方案
回答
是的,第二个代码段是完全有效的。
每次将-autorelease发送给对象时,都会将其添加到最内部的autorelease池中。当池耗尽时,它仅向池中的所有对象发送-release。
自动释放池只是一种便利,它使我们可以将发送-release推迟到"以后"。这种"后期"可能会在多个地方发生,但是在Cocoa GUI应用程序中最常见的是当前运行循环周期的结尾。
回答
是的,没有。我们最终将释放字符串内存,但是如果在垃圾回收(不是内存托管)环境下运行NSAutoreleasePool对象,则使用排水而不是释放将NSAutoreleasePool对象"泄漏"到内存中。这种"泄漏"只会使NSAutoreleasePool的实例像其他任何在GC下没有强指针的对象一样"不可访问",并且该对象将在下一次GC运行时被清除,这很可能直接在调用-drain之后`:
drain In a garbage collected environment, triggers garbage collection if memory allocated since last collection is greater than the current threshold; otherwise behaves as release. ... In a garbage-collected environment, this method ultimately calls objc_collect_if_needed.
否则,它类似于在非GC下-release
的行为,是的。正如其他人所说,-release
在GC下是禁止操作的,因此确保池在GC下正常运行的唯一方法是通过-drain
,而在非GC下的-drain
的工作方式与非GC下的-release
,并且可以说也更清楚地传达了其功能。
我应该指出,语句"用new,alloc或者init调用的任何内容"都不应包含" init"(但应包含" copy"),因为" init"不会分配内存,它只会设置对象(构造函数)时尚)。如果收到分配对象,并且函数仅这样调用init,则不会释放该对象:
- (void)func:(NSObject*)allocd_but_not_init { [allocd_but_not_init init]; }
那不会消耗比我们开始时更多的内存(假设init不会实例化对象,但是无论如何我们都不会对这些对象负责)。
回答
不你错了。该文档明确指出,在非GC环境下,-drain等效于-release,这意味着NSAutoreleasePool将不会泄漏。
回答
NSAutoreleasePool:消耗与释放
由于drain
和release
的功能似乎引起混乱,因此在这里可能需要澄清(尽管在文档中已对此进行了介绍)。
严格来说,从全局角度来看," drain"不等同于" release":
在参考计数的环境中,drain'确实执行与
release'相同的操作,因此,两者在这个意义上是等效的。要强调的是,这意味着如果我们使用drain
而不是release
,则不会泄漏池。
在垃圾收集的环境中,release
是禁止操作的。因此,它没有任何作用。另一方面," drain"包含了一个向收集器的提示,即它应该"根据需要收集"。因此,在垃圾收集的环境中,使用" drain"有助于系统平衡收集扫描。
回答
是的,代码是完美的,如果我们要使用垃圾收集,只需在完成处理后将字符串设置为nil就足够了。垃圾收集不利于应用程序的性能,因此我不建议我们使用它:P
回答
我发现此链接提供了有关何时以及如何使用NSAutoReleasePool的最佳解释:AutoReleasePool