第34条:以“自动释放池”降低内存峰值

Objective-C对象的生命周期取决于其引用计数。

释放对象有两种方式:

  • 调用release方法,使其保留计数立即递减
  • 调用autorelease方法,将其加入”自动释放池“中。自动释放池用于存放那些需要在稍后某个时刻释放的对象。清空自动释放池时,系统会向其中的对象发送release消息。
// 创建自动释放池
@autoreleasepool{
       
  }
    
注意:花括号定义了自动释放池的范围。自动释放池于左花括号处创建,并于对应的右花括号处自动清空。
位于自动释放池范围内的对象,将在此范围末尾处收到release消息。

在执行循环体时,一般会持续有新对象创建出来,并加入自动释放池中。这种对象都要等到循环执行完才会释放。这样一来,在执行循环时,应用程序所占内存量会持续上涨,而等到所有临时对象都释放后,内存用量又会突然下降。

NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
for(NSDictionary *record in databaseRecords){
    EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
    [people addObject:person];
}

这种情况不甚理想,尤其是循环长度无法预知时,再创建出一些临时的EOCPerson对象,它们本该提早回收的。增加一个自动释放池即可解决问题,把循环内的代码包裹在自动释放池块中,那么循环体中自动释放的对象就会在这个池,而不是线程的主池里:

NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
for(NSDictionary *record in databaseRecords){
    @autoreleasepool{
        EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
        [people addObject:person];
    }
}

加上自动释放池之后,就会降低应用程序在执行循环时的内存峰值。因为系统会在块的末尾将临时对象回收掉。如果循环的内存用量不高,则尽量不建立额外的自动释放池,因为自动释放池块还是存在开销(虽然不大)。

在ARC出现之前一般使用NSAutoreleasePool对象,这样可以不用每次循环都清空池,通常用来创建偶尔需要清空的池:

NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
int i = 0;

// 创建自动释放池会被推入栈中,在对象上执行autorelease等于将其放到栈顶的自动释放池中。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(NSDictionary *record in databaseRecords){
    EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
    [people addObject:person];

    // 每执行10次循环,清空一次自动释放池
    if (++i == 10){
        [pool drain];
        i = 0;;
    }
}
// 结束循环后,再次清空自动释放池
[pool drain];

你可能感兴趣的:(第34条:以“自动释放池”降低内存峰值)