概念
AutoreleasePool(自动释放池)是OC中的一种内存自动回收机制,它可以延迟加入AutoreleasePool中的变量release的时机。在正常情况下,创建的变量会在超出其作用域的时候release,但是如果将变量加入AutoreleasePool,那么release将延迟执行。

App启动后,苹果在主线程 RunLoop里注册了两个 Observer,其回调都是_wrapRunLoopWithAutoreleasePoolHandler(),从程序启动到加载完成,主线程对应的runloop会处于休眠状态,等待用户交互来唤醒runloop- 第一个
Observer监视的事件是Entry(即将进入Loop),其回调内会调用_objc_autoreleasePoolPush()创建自动释放池。优先级最高,保证创建释放池发生在其他所有回调之前 - 第二个
Observer监视了两个事件:BeforeWaiting(准备进入休眠)时调用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()释放旧的池并创建新池;Exit(即将退出Loop)时调用_objc_autoreleasePoolPop()来释放自动释放池。优先级最低,保证其释放池子发生在其他所有回调之后。
- 第一个
- 用户的每一次交互都会启动一次
runloop,用于处理用户的所有点击、触摸事件等 runloop在监听到交互事件后,就会创建自动释放池,并将所有延迟释放的对象添加到自动释放池中主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被RunLoop创建好的AutoreleasePool环绕着,所以不会出现内存泄漏,开发者也不必显示创建Pool了。- 在一次完整的runloop结束之前,会向自动释放池中所有对象发送release消息,然后销毁自动释放池
clang 分析
int main(int argc, char * argv[]) {
@autoreleasepool {
}
}
通过clang编译成cpp文件插看实现:
xcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc main.m
int main(int argc, char * argv[]) {
/* @autoreleasepool */ {
__AtAutoreleasePool __autoreleasepool;
}
}
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
通过代码可以看出autoreleasepool在底层实际是调用__AtAutoreleasePool,而__AtAutoreleasePool本质上是一个结构体,其内部包含构造函数__AtAutoreleasePool()与析构函数~__AtAutoreleasePool(),在{}作用域结束后会自动调用析构函数,以便及时创建销毁
###汇编分析
struct LGTest {
LGTest(){
printf("1123 - %s",__func__);
}
~LGTest(){
printf("5667 - %s",__func__);
}
};
int main(int argc, char * argv[]) {
LGTest LGTest;
}
在main函数中添加断点查看汇编

可以看出跟clang编译后一样都是经过objc_autoreleasePoolPush与objc_autoreleasePoolPop
底层原理
在objc源码中是这样注释的
Autorelease pool implementation
- A thread's autorelease pool is a stack of pointers.
线程的自动释放池是指针的堆栈
- Each pointer is either an object to release, or POOL_BOUNDARY which is an autorelease pool boundary.
每个指针都是要释放的对象,或者是POOL_BOUNDARY(哨兵),它是自动释放池的边界。
- A pool token is a pointer to the POOL_BOUNDARY for that pool. When the pool is popped, every object hotter than the sentinel is released.
池令牌是指向该池的POOL_BOUNDARY的指针。弹出池后,将释放比哨点更热的每个对象。
- The stack is divided into a doubly-linked list of pages. Pages are added and deleted as necessary.
堆栈分为两个双向链接的页面列表。根据需要添加和删除页面。
- Thread-local storage points to the hot page, where newly autoreleased objects are stored.
线程本地存储指向热页面,该页面存储新自动释放的对象。
查看源码
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
NEVER_INLINE
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
通过代码可以看出push与pop操作都是基于AutoreleasePoolPage,根据其定义看出自动释放池是页结构,每页的大小为4096字节
//************宏定义************
#define PAGE_MIN_SIZE PAGE_SIZE
#define PAGE_SIZE I386_PGBYTES
#define I386_PGBYTES 4096 /* bytes per 80386 page */
//************类定义************
class AutoreleasePoolPage : private AutoreleasePoolPageData
{
friend struct thread_

本文深入探讨了Objective-C中的AutoReleasePool概念,包括它在RunLoop中的作用,以及通过clang编译后的cpp实现和底层的内存管理原理。文章通过汇编分析展示了AutoReleasePool的push和pop操作,解释了如何存储和释放对象,同时揭示了其与内存页的关系。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



