4-autoreleasepool原理

本文详细探讨了iOS应用中的autoreleasepool机制,包括其工作原理、AutoreleasePoolPage结构、objc_autoreleasePoolPush和objc_autoreleasePoolPop方法,以及autorelease函数在内存管理中的作用。通过源码分析揭示了autoreleasePool如何自动管理对象生命周期和内存释放的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在IOS程序中main.m文件,是整个IOS应用的入口,@autoreleasepool{}这个block包裹了整个应用,对象创建时自动执行autorelease将对象加入到autoreleasepool,进而管理整个IOS应用的内存回收,不用在创建对象的最后再手动release。那么下面从源码的角度来分析autoreleasepool究竟是怎样工作的。

一、@autoreleasepool

@autoreleasepool到底是什么?在命令行中使用xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp 让编译器重新改写以下代码:
在这里插入图片描述
在这里插入图片描述
于是在目录下生成main.cpp文件,删除无用代码,具体如下:
在这里插入图片描述
由上图知道只是声明了__AtAutoreleasePool这样的一个结构,在main.cpp中查找这个结构,代码如下:
在这里插入图片描述
由上图可知,__AtAutoreleasePool创建的时候调用了objc_autoreleasePoolPush并返回第一页的POOL_BOUNDARY(哨兵对象),析构的时候调用objc_autoreleasePoolPop并传入POOL_SENTINEL,所以其实main函数的实际工作应该是这样的:
在这里插入图片描述

二、AutoreleasePool

由上节可知@autoreleasepool只是调用了objc_autoreleasePoolPush和objc_autoreleasePoolPop,这两个函数都在NSObject.mm文件中,代码如下:
在这里插入图片描述
所以下面分为4个小节,来详细说明AutoreleasePool如何实现:
-. AutoreleasePoolPage的结构
-. objc_autoreleasePoolPush方法
-. POOL_BOUNDARY(哨兵对象)
-. objc_autoreleasePoolPop
-. autorelease

2.1 AutoreleasePoolPage结构

AutoreleasePool实际就是AutoreleasePoolPage组成的双向链表,AutoreleasePoolPage是一个是一个C++类(NSObject.mm),代码如下:
在这里插入图片描述
AutoreleasePoolPage继承于AutoreleasePoolPageData结构体(NSObject-internal.h),所有有关的Page数据都放在了这个结构体中:
在这里插入图片描述
假设一个AutoreleasePoolPage 被初始化在内存的 0x100816000 ~ 0x100817000 中,它在内存中的结构如下:
在这里插入图片描述

2.2 POOL_BOUNDARY(哨兵对象)

POOL_BOUNDARY只是 nil 的别名。每个Page都有一个POOL_BOUNDARY,相当于Page有关信息和obj对象的分界线。
在这里插入图片描述
在执行objc_autoreleasePoolPush方法的时候会把POOL_BOUNDARY加入到第一页,而且返回这个哨兵对象。
在这里插入图片描述
在objc_autoreleasePoolPop调用时,传入的就是这个POOL_BOUNDARY,向自动释放池中的对象发送 release 消息,直到第一个 POOL_SENTINEL。
在这里插入图片描述

2.3 objc_autoreleasePoolPush方法

objc_autoreleasePoolPush作用是创建自动释放池的第一页,并返回第一页的POOL_BOUNDARY(哨兵对象)。代码如下:
在这里插入图片描述
由上图可知,它调用了AutoreleasePoolPage 的类方法 push方法,代码如下:
在这里插入图片描述
在这里会进入一个比较关键的方法 autoreleaseFast,并传入哨兵对象 POOL_SENTINEL。
在这里插入图片描述

  1. 情况一(页面存在且不满):
    调用add方法将对象添加到自动释放池,核心逻辑就是将obj添加到next位置,next指针后移,代码如下:
    在这里插入图片描述
  2. 情况二(页面存在且装满):
    调用autoreleaseFullPage,创建新page,链接到琏表最后,并设置成hotPage,再进行add,这里返回的就是POOL_BOUNDARY,代码如下:
    在这里插入图片描述
  3. 情况三(页面不存在):
    调用autoreleaseNoPage(NSObject.mm),创建新page,并设置成hotPage再进行add,这里返回的就是POOL_BOUNDARY,这里删除了一些debug代码,具体代码如下:
    在这里插入图片描述

2.4 objc_autoreleasePoolPop 方法

objc_autoreleasePoolPop作用对自动释放池中的对象发送release消息,一直到传入的*ctxt指针,但是在整个工程并没有发现传入其他对象的例子。不过在这个方法中传入其它的指针也是可行的,会将自动释放池释放到相应的位置。代码如下:
在这里插入图片描述
由上图可知,它调用了AutoreleasePoolPage 的类方法 POP(NSObject.mm)方法,删除了一些debug代码,具体代码如下:
在这里插入图片描述
在这里插入图片描述
再看popPage(NSObject.mm)方法,删除了一些debug代码,具体代码如下:
在这里插入图片描述
真正释放obj到stop的方法是releaseUntil(NSObject.mm),删除了一些debug代码,具体实现如下:
在这里插入图片描述
对page页面进行内存释放的是kill方法,目的删除当前page后的所有page,具体代码如下:
在这里插入图片描述

2.5 autorelease 方法

  1. autorelease的作用就是将当前对象加入到所在的自动释放池。从NSObject的autorelease(objc-object.h)开始执行:
    在这里插入图片描述
  2. 执行rootAutorelease方法(objc-object.h):
    在这里插入图片描述
  3. 执行rootAutorelease2方法(NSObject.mm):
    在这里插入图片描述
  4. 执行AutoreleasePoolPage的autorelease(NSObject.mm)方法:
    在这里插入图片描述
  5. 执行AutoreleasePoolPage的 autoreleaseFast (NSObject.mm)方法,将obj加入到自动释放池,autoreleaseFast参考2.3节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值