一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
对象压栈
进入objc_autoreleasePoolPush函数
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
进入AutoreleasePoolPage命名空间下的push函数
static inline void *push()
{
id *dest;
if (slowpath(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);
return dest;
}
DebugPoolAllocation:当自动释放池按顺序弹出时停止,并允许堆调试器跟踪自动释放池- 不存在,调用
autoreleaseNewPage函数,从一个新的池页开始创建 - 否则,调用
autoreleaseFast函数,将哨兵对象压栈
autoreleaseFast
进入autoreleaseFast函数
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);
}
}
- 如果存在
page,并且没有存满,调用add函数 - 如果存在
page,但存储已满,调用autoreleaseFullPage函数 - 否则,不存在
page,调用autoreleaseNoPage函数
autoreleaseNoPage
进入autoreleaseNoPage函数
static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
// "No page" could mean no pool has been pushed
// or an empty placeholder pool has been pushed and has no contents yet
ASSERT(!hotPage());
bool pushExtraBoundary = false;
...
// We are pushing an object or a non-placeholder'd pool.
// Install the first page.
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push a boundary on behalf of the previously-placeholder'd pool.
if (pushExtraBoundary) {
page->add(POOL_BOUNDARY);
}
// Push the requested object or pool.
return page->add(obj);
}
- 调用
AutoreleasePoolPage构造函数,创建新页 - 设置为热页面
pushExtraBoundary为YES,哨兵对象压栈- 对象压栈
进入
AutoreleasePoolPage构造函数
AutoreleasePoolPage(AutoreleasePoolPage *newParent) :
AutoreleasePoolPageData(begin(),
objc_thread_self(),
newParent,
newParent ? 1+newParent->depth : 0,
newParent ? newParent->hiwat : 0)
{
if (objc::PageCountWarning != -1) {
checkTooMuchAutorelease();
}
if (parent) {
parent->check();
ASSERT(!parent->child);
parent->unprotect();
parent->child = this;
parent->protect();
}
protect();
}
- 通过父类
AutoreleasePoolPageData进行初始化 begin:获取对象压栈的起始位置objc_thread_self:通过tls获取当前线程- 链接双向链表
进入
begin函数
id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this));
}
sizeof(*this):大小取决于自身结构体中的成员变量- 返回对象可压栈的真正开始地址,在成员变量以下 进入AutoreleasePoolPageData的定义
{
...
magic_t const magic;
__unsafe_unretained id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
...
};
magic:16字节next、thread、parent、child:各占8字节depth、hiwat:各占4字节- 共占
56字节进入magic_t的定义
struct magic_t {
static const uint32_t M0 = 0xA1A1A1A1;
# define M1 "AUTORELEASE!"
static const size_t M1_len = 12;
uint32_t m[4];
...
# undef M1
};
- 结构体的创建在堆区申请内存,而静态成员存储在静态区,不占结构体大小
16字节来自于uint32_t数组 进入objc_thread_self函数
static inline pthread_t objc_thread_self()
{
return (pthread_t)tls_get_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
}
- 通过
tls获取当前线程
autoreleaseFullPage
进入autoreleaseFullPage函数
id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)
{
// The hot page is full.
// Step to the next non-full page, adding a new page if necessary.
// Then add the object to that page.
ASSERT(page == hotPage());
ASSERT(page->full() || DebugPoolAllocation);
do {
if (page->child) page = page->child;
else page = new AutoreleasePoolPage(page);
} while (page->full());
setHotPage(page);
return page->add(obj);
}
- 遍历链表,找到最后一个空白的子页面
- 对其进行创建新页
- 设置为热页面
- 添加对象 形成以下数据结构:
add
进入add函数
id *add(id obj)
{
ASSERT(!full());
unprotect();
id *ret;
...
ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
#if SUPPORT_AUTORELEASEPOOL_DEDUP_PTRS
// Make sure obj fits in the bits available for it
ASSERT(((AutoreleasePoolEntry *)ret)->ptr == (uintptr_t)obj);
#endif
done:
protect();
return ret;
}
- 使用
*next++进行内存平移 - 将对象压栈
autoreleaseNewPage
进入autoreleaseNewPage函数
id *autoreleaseNewPage(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page) return autoreleaseFullPage(obj, page);
else return autoreleaseNoPage(obj);
}
- 获取热页面
- 存在,调用
autoreleaseFullPage函数 - 否则,不存在
page,调用autoreleaseNoPage函数