int main(int argc, const char * argv[]) {
@autoreleasepool {
__unused RTStudent *stu = [[[RTStudent alloc] init] autorelease];
}
return 0;
}
使用xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
转为C++代码,再整理后得
int main(int argc, const char * argv[]) {
{
__AtAutoreleasePool __autoreleasepool;
RTStudent *stu = objc_msgSend(objc_msgSend(objc_msgSend(objc_getClass("RTStudent"), sel_registerName("alloc")), sel_registerName("init")), sel_registerName("autorelease"));
}
return 0;
}
其中__AtAutoreleasePool
是一个结构体:
struct __AtAutoreleasePool {
__AtAutoreleasePool() {
atautoreleasepoolobj = objc_autoreleasePoolPush();
} //构造函数
~__AtAutoreleasePool() {
objc_autoreleasePoolPop(atautoreleasepoolobj)
} //析构函数
void * atautoreleasepoolobj;
};
将objc_msgSend
转为OC方法:
int main(int argc, const char * argv[]) {
{
__AtAutoreleasePool __autoreleasepool;
RTStudent *stu = [[[RTStudent alloc] init] autorelease];
}
return 0;
}
在main
函数中可见@autoreleasepool
的作用是在{}
中声明了一个__AtAutoreleasePool __autoreleasepool
结构体对象,会自动调用__AtAutoreleasePool
的构造函数__AtAutoreleasePool()
,就又调用了objc_autoreleasePoolPush()
函数,当出了{}
的作用域时,会销毁局部变量__autoreleasepool
,此时就会调用析构函数~__AtAutoreleasePool()
,然后就调用了objc_autoreleasePoolPop()
函数,可见autorelease
的对象,会自动销毁应该和push
和pop
有关了
在NSObject.mm文件中找到objc_autoreleasePoolPush()
和objc_autoreleasePoolPop()
void * objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
具体实现是调用了AutoreleasePoolPage
类的push
和pop
方法,进入方法查看后,发现不论是push还是pop都主要和AutoreleasePoolPage
对象在管理
class AutoreleasePoolPage
{
# define EMPTY_POOL_PLACEHOLDER ((id*)1)
# define POOL_BOUNDARY nil
static pthread_key_t const key = AUTORELEASE_POOL_KEY;
static uint8_t const SCRIBBLE = 0xA3; // 0xA3A3A3A3 after releasing
static size_t const SIZE =
#if PROTECT_AUTORELEASEPOOL
PAGE_MAX_SIZE; // must be multiple of vm page size
#else
PAGE_MAX_SIZE; // size and alignment, power of 2
#endif
static size_t const COUNT = SIZE / sizeof(id);
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
那么从哪个地址开始存放需要autorelease的对象呢?它有一个方法begin()
,可以看到,this
的起始地址+自己的成员所占的大小,就是存放需要autorelease的对象
的起始地址
id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this));
}
那么结束地址在哪里呢?它有一个方法end()
,可以看到,this
的起始地址+自己的数据结构的大小
id * end() {
return (id *) ((uint8_t *)this+SIZE);
}
由于一个page对象只有4096字节,所以当需要autorelease对象太多的话,一个page装不下,所以可能一个pool中有很多个page对象,而child
指针指向的就是下一个page对象,parent
指向的就是上一个page对象
POOL_BOUNDARY
入栈,并且返回其存放的内存地址,也就是begin()的地址,并把这个地址返回给__AtAutoreleasePool
对象的atautoreleasepoolobj
,然后next指向下一个地址 static inline void *push()
{
id *dest;
if (DebugPoolAllocation) {
// Each autorelease pool starts on a new pool page.
dest = autoreleaseNewPage(POOL_BOUNDARY);
} else {
dest = autoreleaseFast(POOL_BOUNDARY);
}
assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY); // POOL_BOUNDARY == *atautoreleasepoolobj
return dest;
}
//调用了rootAutorelease()
- (id)autorelease {
return ((id)self)->rootAutorelease();
}
//这个方法里调用了rootAutorelease2函数
inline id objc_object::rootAutorelease() {
if (isTaggedPointer()) return (id)this;
if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
return rootAutorelease2();
}
//这个方法里调用了AutoreleasePoolPage的autorelease函数
__attribute__((noinline,used)) id objc_object::rootAutorelease2() {
assert(!isTaggedPointer());
return AutoreleasePoolPage::autorelease((id)this);
}
//这个方法里调用了page->add(obj) 将obj入栈
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj); //将这个对象入栈
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
atautoreleasepoolobj
,就从最后一个入栈的autorelease对象开始调用release方法,直到遇到POOL_BOUNDARY
这个地址,结束释放. static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop;
..........
page = pageForPointer(token);
stop = (id *)token;
if (*stop != POOL_BOUNDARY) {
if (stop == page->begin() && !page->parent) {
// Start of coldest page may correctly not be POOL_BOUNDARY:
// 1. top-level pool is popped, leaving the cold page in place
// 2. an object is autoreleased with no pool
} else {
// Error. For bincompat purposes this is not
// fatal in executables built with old SDKs.
return badPop(token);
}
}
if (PrintPoolHiwat) printHiwat();
page->releaseUntil(stop);
.........
}
//释放
void releaseUntil(id *stop)
{
while (this->next != stop) {
AutoreleasePoolPage *page = hotPage();
while (page->empty()) {
page = page->parent;
setHotPage(page);
}
page->unprotect();
id obj = *--page->next;
memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
page->protect();
if (obj != POOL_BOUNDARY) {
objc_release(obj);
}
}
...........
}
AutoreleasePoolPage类中有一个打印的方法
void _objc_autoreleasePoolPrint(void) {
AutoreleasePoolPage::printAll();
}
虽然_objc_autoreleasePoolPrint
没有暴露出来,但可以使用extern void __objc_autoreleasePoolPrint(void);
来声明,然后使用
extern void _objc_autoreleasePoolPrint(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
__unused RTStudent *stu = [[[RTStudent alloc] init] autorelease];
__unused RTStudent *stu2 = [[[RTStudent alloc] init] autorelease];
@autoreleasepool {
__unused RTStudent *stu = [[[RTStudent alloc] init] autorelease];
@autoreleasepool {
__unused RTStudent *stu = [[[RTStudent alloc] init] autorelease];
__unused RTStudent *stu2 = [[[RTStudent alloc] init] autorelease];
_objc_autoreleasePoolPrint();
}
}
}
return 0;
}
objc[88455]: ##############
objc[88455]: AUTORELEASE POOLS for thread 0x100399380
objc[88455]: 8 releases pending.
objc[88455]: [0x100801000] ................ PAGE (hot) (cold)
objc[88455]: [0x100801038] ################ POOL 0x100801038
objc[88455]: [0x100801040] 0x10054f4a0 RTStudent
objc[88455]: [0x100801048] 0x100422ae0 RTStudent
objc[88455]: [0x100801050] ################ POOL 0x100801050
objc[88455]: [0x100801058] 0x100403100 RTStudent
objc[88455]: [0x100801060] ################ POOL 0x100801060
objc[88455]: [0x100801068] 0x100423740 RTStudent
objc[88455]: [0x100801070] 0x100405aa0 RTStudent
objc[88455]: ##############
可以看到,使用一次@autoreleasepool{}
,即创建一个__AtAutoreleasePool
对象,就会调用一次push
,放进一个POOL_BOUNDARY
,page对象
的next指针
指向下一个地址,然后把需要autorelease对象
放入page中,next指针
移动相应数量的地址,当一个page没有满autorelease对象
的时候,多个释放池会共用这个page,直到它满
了,才会创建新的page对象
- (void)viewDidLoad {
[super viewDidLoad];
@autoreleasepool {
__unused RTPerson *obj = [[[RTPerson alloc] init] autorelease];
}
NSLog(@"%s",__func__);
}
//打印信息
2019-05-27 22:27:16.307421+0800 Test[91865:5115718] dealloc
2019-05-27 22:27:16.307560+0800 Test[91865:5115718] -[ViewController viewDidLoad]
- (void)viewDidLoad {
[super viewDidLoad];
__unused RTPerson *obj = [[[RTPerson alloc] init] autorelease];
NSLog(@"%s",__func__);
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"%s",__func__);
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"%s",__func__);
}
//打印信息
2019-05-27 22:29:21.045179+0800 Test[91982:5120141] -[ViewController viewDidLoad]
2019-05-27 22:29:21.045454+0800 Test[91982:5120141] -[ViewController viewWillAppear:]
2019-05-27 22:29:21.048347+0800 Test[91982:5120141] dealloc
2019-05-27 22:29:21.058970+0800 Test[91982:5120141] -[ViewController viewDidAppear:]
打印当前的runloop的observers时,会发现有两个observe和AutoreleasePool相关
"{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10b8871b1), context = {type = mutable-small, count = 1, values = (\n\t0 : <0x7f8baa009058>\n)}}",
activities = 0x1 即 kCFRunLoopEntry = (1UL << 0) ,当runloop进入的时候,会调用回调,调用objc_autoreleasePoolPush()函数
"{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10b8871b1), context = {type = mutable-small, count = 1, values = (\n\t0 : <0x7f8baa009058>\n)}}"
kCFRunLoopBeforeWaiting = (1UL << 5) => 32
kCFRunLoopExit = (1UL << 7) => 128
activities = 0xa0 (十进制的160) 即 kCFRunLoopBeforeWaiting | kCFRunLoopExit
当runloop即将休眠和退出的时候调用回调,调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()函数
当runloop即将退出的时候调用回调,会调用objc_autoreleasePoolPop()函数
我的开发笔记