内存并不完全泄漏:它已经准备好被释放,但它永远没有机会被释放。
ARC 建立在 Objective-C 的手动内存管理规则之上。基本规则是“调用的对象/函数init
拥有新实例”,并且所有者必须release
当对象不再需要它时。
对于创建对象的便捷方法来说这是一个问题,例如[NSData dataWithContentsOfFile:]
。该规则意味着NSData
类拥有该实例,因为它调用了init
在上面。一旦返回该值,该类将不再需要该对象,并且需要释放它。但是,如果这种情况发生在被调用者有机会保留实例之前,则该实例将在任何事情发生之前就消失。
为了解决这个问题,Cocoa 引入了autorelease
方法。此方法将对象的所有权转移到最后设置的自动释放池。当您退出自动释放池的作用域时,自动释放池将被“耗尽”。
Cocoa/AppKit/UIKit 会自动围绕事件处理程序设置自动释放池,因此您通常不需要担心这一点。但是,如果您有一个长时间运行的方法,这就会成为一个问题。
您可以使用以下方式声明自动释放池@autoreleasepool
陈述:
@autoreleasepool
{
// code here
}
在右括号中,自动释放池收集的对象被释放(如果没有其他人引用它们,则可能会释放它们)。
因此,您需要将循环体包含在该语句中。
这是一个例子。这段代码在我的计算机上每秒“泄漏”大约 10 MB,因为执行过程永远不会离开@autoreleasepool
scope:
int main(int argc, const char * argv[])
{
@autoreleasepool
{
while (true)
{
NSString* path = [NSString stringWithFormat:@"%s", argv[0]];
[NSData dataWithContentsOfFile:path];
}
}
}
另一方面,这样一来,内存使用量就会保持稳定,因为执行会留下@autoreleasepool
每次循环迭代结束时的范围:
int main(int argc, const char * argv[])
{
while (true)
{
@autoreleasepool
{
NSString* path = [NSString stringWithFormat:@"%s", argv[0]];
[NSData dataWithContentsOfFile:path];
}
}
}
对于长循环来说,在循环条件中创建对象很尴尬,因为这些对象不会被内部拾取。@autoreleasepool
。您需要将这些放入@autoreleasepool
范围也是如此。
返回
每当我们return
一个对象(也许是Swift
),我们需要注册到最近的@autoreleasepool
阻止(通过调用autorelease
防止内存泄漏的方法,根据所有权规则),但如今ARC
自动为我们做这件事;
每当ARC
残疾人;使用后alloc
and/or init
, call autorelease
手动,例如:
- (NSString *)fullName {
NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
self.firstName, self.lastName] autorelease];
return string;
}