autorelease 的伪代码实现
等同于以下代码
1 2 3 4 5
| - (id)autorelease { [NSAutoreleasePool addObject:self]; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| + (void)addObject:(id)anObj { NSAutoreleasePool *pool = 获取正在使用中的 pool; if (pool != nil) { [pool addObject:anObj]; } }
- (void)addObject:(id)anObj { [array addObject:anObj]; }
|
其中关于获取正在使用中的 pool,以下例子的 obj 在调用 autorelease 时取到的 autoreleasepool 就是 poo2
1 2 3 4 5 6 7 8
| NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
NSObject *obj = [[NSObject alloc] init]; [obj autorelease]
[poo1 drain]; [poo2 drain];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (void)drain { [self dealloc]; }
- (void)dealloc { [self emptyPool]; [array release]; }
- (void)emptyPool { for (id obj in array) { [obj release]; } }
|
autorelease 苹果的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class AutoreleasePoolPage { static inline void *push() { }
static inline id autorelease(id obj) { AutoreleasePoolPage *autoreleasePoolPage = 取得正在使用的 AutoreleasePoolPage 实例; autoreleasePoolPage->add(obj); } id *add(id obj) { }
static inline void *pop(void *token) { releaseAll(); } void releaseAll() { } }; void *objc_autoreleasePoolPush(void) { return AutoreleasePoolPage::push(); } void objc_autoreleasePoolPop(void *ctxt) { AutoreleasePoolPage::pop(ctxt); } id *objc_autorelease(id obj) { return AutoreleasePoolPage::autorelease(obj); }
|
1 2 3 4 5 6 7 8 9
| NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
|
AutoreleasePool 的底层实现
- AutoreleasePool 是由一个个 AutoreleasePoolPage 组成的双向链表
- AutoreleasePoolPage 内部维护一个栈;栈满的时候会新建一个 AutoreleasePoolPage 节点
- AutoreleasePool Push 时会压入一个边界对象表示一个 AutoreleasePool 的开始,Pop 时会清理堆栈直到遇到一个边界对象;边界对象是界定 AutoreleasePool 的分割线
AutoreleasePool 与 RunLoop
App 启动后,苹果在主线程 RunLoop 里注册了两个 Observer,区别是优先级不同
第一个 Observer 优先级最高,保证创建释放池发生在其他所有回调之前,监视了一个事件:
- Entry(即将进入 Loop),其回调内会调用
_objc_autoreleasePoolPush()
创建自动释放池。
第二个 Observer 优先级最低,保证其释放池子发生在其他所有回调之后,监视了两个事件:
- BeforeWaiting(准备进入休眠)时调用
_objc_autoreleasePoolPop()
和 _objc_autoreleasePoolPush()
释放旧的池并创建新池;
- Exit(即将退出 Loop) 时调用
_objc_autoreleasePoolPop()
来释放自动释放池。
在主线程执行的代码,通常是写在诸如事件回调、Timer 回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了
参考文章