在Objective-C
的引用计数架构中,有一项特性叫做“自动释放池”(autoreleasepool)
。释放对象有两种方式:一种是 调用release
方法,使其保留计数立即递减;另一种是调用autorelease
方法,将其加人“自动 释放池”中。自动释放池用于存放那些需要在稍后某个时刻释放的对象。清空(drain)
自动释放池时,系统会向其中的对象发送release
消息。
创建自动释放池的语句为:
@autoreleasepool{
// ....
}
我们来看下面这个例子:
@autoreleasepool {
NSString *string = [NSString stringWithFormat: @"1 = %i", 1];
@autoreleasepool {
NSNumber *number = [NSNumber numberWithlnt:1];
}
}
上面这个例子展示了基本的用法,自动释放池于左花括号处创建, 并于对应的右花括号处自动清空。位于自动释放池范围内的对象,将在此范围末尾处收到release
消息。自动释放池可以嵌套。系统在自动释放对象时,会把它放到最内层的池里。
autoreleasepool
的常见用法为降低程序的内存峰值,比如下面这个代码:
NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in databaseRecords) {
EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
[people addObject:person];
}
上述代码,因为for
语句会不断的创建person
对象,造成应用程序内存不断上涨,在执行完for
语句后又会将所有临时对象都释放,造成内存的突然上涨与下降。这些临时对象本可以提前回收的,所以我们应该这么写:
NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in databaseRecords) {
@autoreleasepool{
EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
[people addObject:person];
}
}
加上这个自动释放池之后,应用程序在执行循环时的内存峰值就会降低,不再像原来那么高了。内存峰值(high-memory waterline)
是指应用程序在某个特定时段内的最大内存用量 (highest memory footprint)
。新增的自动释放池块可以减少这个峰值,因为系统会在块的末尾把某些对象回收掉。而刚才提到的那种临时对象,就在回收之列。
自动释放池机制就像“栈”(stack)
一样。系统创建好自动释放池之后,就将其推入栈中, 而清空自动释放池,则相当于将其从栈中弹出。在对象上执行自动释放操作,就等于将其放入栈顶的那个池里。
现在我们创建一个iOS程序之后,系统会默认有一个main.m文件
其中有代码:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
我们用自动释放池来包裹应用程序的主入口点(main application entry point)
,除了上述主动添加了一个释放池,我们一般不需要主动添加,系统创建的线程一般默认都有自动释放池。
@autordeaSepool
语法还有个好处:每个自动释放池均有其范围,可以避免无意间误用了那些在清空池后已为系统所回收的对象。例如:
@autoreleasepool {
id object = [self createObject];
}
[self useObject:object];
上述代码无法编译,因为object
变量出了自动释放池块的外围后就不可用了(已经被释放),所以在调用“useObject:”
方法时不能用它做参数。
要点
- 自动释放池排布在栈中,对象收到
autorelease
消息后,系统将其放入最顶端的池里。
- 合理运用自动释放池,可降低应用程序的内存峰值。
@autoreleasepool
这种新式写法能创建出更为轻便的自动释放池。