@autoreleasepool-内存的分配与释放

@autoreleasepool-内存的分配与释放

开发过iOS、Mac的朋友应该对“ @autoreleasepool ”不陌生。只要在Xcode里建立一个工程,就能看到下面这样的代码:

//iOS program
int main(int argc, char * argv[]) {
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}
//Command line program
int main(int argc, const char *argv[]) {
  @autoreleasepool {
    //...
  }
  return 0;
}

看,每一个 main 函数的主体都被 @autoreleasepool 的Block块包在里面,也就是说,接下来全部的对象建立都在这个block里面。

那么, @autoreleasepool 的做用究竟是什么呢?咱们开发中能够用它来作什么呢?

能够在某些状况下,大幅度下降程序的内存占用,以下图:


测试的内容:500000次循环,每次循环建立一个NSNumber实例和两个NSString实例。
图:红线表示没有用 @autoreleasepool 时的内存占用。
图:绿线表示用了 @autoreleasepool 优化后的内存占用!
效果是否是很明显!

代码Github地址: AutoReleasePoolTestExample Xcode 6, iOS 8, iPhone 5模拟器.

MRC 与 ARC

MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting),分别对应着手动引用计数和自动引用计数。

对!是计数,不是“ GC、垃圾回收 ”什么的,就是说,在Objective-C的开发中,ARC不表明像Java那样有GC作垃圾回收,因此本质上仍是要“手动”管理内存的。也就是说,咱们在ARC环境下写的代码,不用本身手动插入“ retain、release这些消息 ”,ARC会在编译时为咱们在合适的位置插入,释放没必要要的内存。

而 @autoreleasepool 就跟对象的 release 密切相关。

@autoreleasepool 干了啥

在MRC时代,若是咱们想先retain一个对象,可是并不知道在何时能够release它,咱们能够像下面这么作:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSString* str = [[[NSString alloc] initWithString:@"tutuge"] autorelease];
//use str...

[pool release];
//str is released
就是说,咱们能够在建立对象的时候给对象发送“ autorelease ”消息,而后当 NSAutoreleasePool 结束的时候,“标记过”autorelease的对象都会被“ release ”掉,也就是会被释放掉。

可是在ARC时代,咱们不用手动发送 autorelease 消息,ARC会自动帮咱们加。而这个时候, @autoreleasepool 作的事情,跟 NSAutoreleasePool 就如出一辙了。

何时用@autoreleasepool

根据 Apple的文档 ,使用场景以下:

写基于命令行的的程序时,就是没有UI框架,如AppKit等Cocoa框架时。
写循环,循环里面包含了大量临时建立的对象。(本文的例子)
建立了新的线程。(非Cocoa程序建立线程时才须要)
长时间在后台运行的任务。
利用@autoreleasepool优化循环

利用@autoreleasepool优化循环的内存占用,我以为最有用的一点,下面就说说这个点。

以下面的循环,次数很是多,并且循环体里面的对象都是临时建立使用的,就能够用 @autoreleasepool 包起来,让每次循环结束时,能够及时的释放临时对象的内存。

//来自Apple文档,见参考
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
  @autoreleasepool {
    NSError *error;
    NSString *fileContents = [NSString stringWithContentsOfURL:url
                     encoding:NSUTF8StringEncoding error:&error];
    /* Process the string, creating and autoreleasing more objects. */
  }
}

这么作的效果是极其显著地,就如本文最开始的图同样,能够本身把示例工程下回来运行下试试~

总结

@autoreleasepool看起来很不“起眼”,日常开发很容易就忽略它了,可是仔细一看,确如此有用~

参考
相关文章
相关标签/搜索