


intmain(int argc, constchar * argv[]) {@autoreleasepool {}return 0;}
main.cpp文件, 代码被转换为C++文件:intmain(int argc, constchar * argv[]) {/* @autoreleasepool */ {__AtAutoreleasePool __autoreleasepool;}return 0;}
可以看到@autoreleasepool实际就是由__AtAutoreleasePool类创建管理的,作用域开始时(创建时)会调用这个类的构造函数,作用域结束时,会调用这个类的析构函数
struct __AtAutoreleasePool {// 构造函数--调用push方法__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}// 析构函数--调用pop方法~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}void * atautoreleasepoolobj;};
构造函数会调用objc_autoreleasePoolPush函数,并返回atautoreleasepoolobj对象。
析构函数会调用objc_autoreleasePoolPop函数,并传入atautoreleasepoolobj对象。
这部分的细节,可以通过查看objc的源码,查看objc_autoreleasePoolPush和objc_autoreleasePoolPop函数:
void * objc_autoreleasePoolPush(void){return AutoreleasePoolPage::push();}void objc_autoreleasePoolPop(void *ctxt){AutoreleasePoolPage::pop(ctxt);}
关于AutoreleasePoolPage类,可以通过objc的源码中查看到类的结构,这里总结一下:
自动释放池是由多个AutoreleasePoolPage组成的双向链表结构,AutoreleasePoolPage中有2个指针分配是parent和child指针,对应指向上一页和下一页(Page)。
当一个Page的空间(一页4096字节)占满时, 会创建一个新的AutoreleasePoolPage对象并添加到链表中,
哨兵对象(POOL_BOUNDARY)
在一个AutoreleasePoolPage的结构体中有一个边界对象(哨兵对象):POOL_BOUNDARY这个边界对象实际一个起的一个别名(本质还是nil),它就是起到一个标识的作用。
当调用objc_autoreleasePoolPush方法,会将POOL_BOUNDARY放到当前的page的栈顶,并且返回这个哨兵对象。
当调用objc_autoreleasePoolPop方法,会将此哨兵对象以参数传入,这样会在自动释放池对这个池中的对象发送release消息,直到找到第一个哨兵对象为止。
对于有大量临时内存对象创建时,比如一个超大的for循环中alloc了一堆对象时, 我们就需要主动添加@autoreleasepool{}方法来管理,
这也就是手动干预释放情况,另外@autoreleasepool{}是可以相互嵌套的, 实际对应上边的page链表来说,就是插入了多个的哨兵对象。
手动创建的@autoreleasepool{}会在“}”结束时释放对象。
另外,autorelease对象释放还有系统干预释放的情况,上面介绍的是手动干预释放的情况。
对于系统干预释放是不指定@autoreleasepool,所有的autoreleasepool对象都是由主线程的RunLoop创建的@autoreleasepool来管理。在Runloop事件进入Entry时,创建AutoreleasePoolPage对象,也就是调用
objc_autoreleasePoolPush方法,在即将休息时,也就是RunLoop进入BeforeWaiting阶段,会调用objc_autoreleasePoolPop方法来释放内存。并创建一个新的AutoreleasePoolPage对象, 最后在RunLoop进入到exit时,会调用objc_autoreleasePoolPop方法来释放内存。
NSNumber *n1 = @1,NSString *str = [NSString stringWithFormat:@"Hi"];NSLog(@"%p - %@ - %@ - 0x%lx",str,str,str.class,ssl_objc_decodeTaggedPointer(str));
夜雨聆风