据我了解,使用alloc,new或copy创建的任何内容都需要手动释放。 例如:
1 2 3 4 5 6
| int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
} |
我的问题是,这样难道不是同样有效吗?:
1 2 3 4 5 6 7 8
| int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
} |
是的,您的第二个代码段是完全有效的。
每次将-autorelease发送给对象时,都会将其添加到最内部的autorelease池中。当池耗尽时,它仅向池中的所有对象发送-release。
自动释放池只是一种便利,它使您可以将发送-释放推迟到"以后"。"后期"可能会在多个地方发生,但是在Cocoa GUI应用程序中最常见的是当前运行循环周期的结尾。
NSAutoreleasePool:消耗与释放
由于drain和release的功能似乎引起混乱,因此在这里可能需要澄清(尽管在文档中已对此进行了介绍)。
严格来说,从大角度看,drain不等同于release:
在引用计数的环境中,drain确实执行与release相同的操作,因此两者在此意义上是等效的。要强调的是,这意味着如果使用drain而不是release,则不会泄漏池。
在垃圾回收的环境中,release是空操作。因此,它没有任何作用。另一方面,drain包含向收集器的提示,提示它应"根据需要收集"。因此,在垃圾回收的环境中,使用drain有助于系统平衡回收扫描。
如前所述,您的第二个代码段是正确的。
我想提出一种使用自动释放池的更简洁的方法,该池适用于所有环境(引用计数,GC,ARC),并且还可以避免浪费/释放混乱:
1 2 3 4 5 6 7
| int main(void) {
@autoreleasepool {
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
}
} |
在上面的示例中,请注意@autoreleasepool块。在此处记录。
不你错了。该文档明确指出,在非GC环境下,-drain等效于-release,这意味着NSAutoreleasePool将不会泄漏。
向对象发送自动释放而不是释放,至少可以延长该对象的寿命,直到耗尽池本身为止(如果随后保留该对象,则可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次将对象放入池中时都会收到释放消息。
我从苹果那里读到的东西:
"在自动释放池块的末尾,向在该块内接收到自动释放消息的对象发送释放消息-每次在该块内向其发送自动释放消息时,对象都会收到释放消息。"
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
是的,没有。您最终将释放字符串内存,但是如果在垃圾回收(非内存托管)环境下运行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.
否则,它类似于-release在非GC下的行为,是的。如其他人所述,-release在GC下是无操作的,因此确保池在GC下正常运行的唯一方法是通过-drain,而在非GC下,-drain的工作方式与在下的-release完全相同。非GC,并且可以说也更清楚地传达了其功能。
我应该指出,您的语句"用new,alloc或init调用的任何内容"都不应包含" init"(但应包含" copy"),因为" init"不分配内存,它只会设置对象(构造函数)时尚)。如果收到分配对象并且函数仅这样调用init,则不会释放该对象:
1 2 3 4
| - (void)func:(NSObject*)allocd_but_not_init
{
[allocd_but_not_init init];
} |
这不会消耗比您开始时更多的内存(假设init不会实例化对象,但是无论如何您都不会对这些对象负责)。