一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
autorelease
进入objc_autorelease
函数
id
objc_autorelease(id obj)
{
if (obj->isTaggedPointerOrNil()) return obj;
return obj->autorelease();
}
- 当前对象为
TaggedPointer
或nil
,直接返回 - 否则,调用对象的
autorelease
函数 进入autorelease
函数
inline id
objc_object::autorelease()
{
ASSERT(!isTaggedPointer());
if (fastpath(!ISA()->hasCustomRR())) {
return rootAutorelease();
}
return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(autorelease));
}
- 如果是自定义类,调用
rootAutorelease
函数 进入rootAutorelease
→rootAutorelease2
→AutoreleasePoolPage::autorelease
函数
inline id
objc_object::rootAutorelease()
{
if (isTaggedPointer()) return (id)this;
if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
return rootAutorelease2();
}
id
objc_object::rootAutorelease2()
{
ASSERT(!isTaggedPointer());
return AutoreleasePoolPage::autorelease((id)this);
}
static inline id autorelease(id obj)
{
ASSERT(!obj->isTaggedPointerOrNil());
id *dest __unused = autoreleaseFast(obj);
#if SUPPORT_AUTORELEASEPOOL_DEDUP_PTRS
ASSERT(!dest || dest == EMPTY_POOL_PLACEHOLDER || (id)((AutoreleasePoolEntry *)dest)->ptr == obj);
#else
ASSERT(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
#endif
return obj;
}
- 调用
autoreleaseFast
函数,对象压栈
池页容量
自动释放池采用分页的方式存储对象,因为对象在频繁压栈和出栈的过程中,产生异常,值会影响当前页面,不会影响到整个自动释放池
并且自动释放池分页管理,每页之前的地址可以不连续,它们可以使用双向链表找到父页面和子页面。如果所有对象都使用一页存储,为了保证地址的连续性,每次扩容会相对繁琐和耗时
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 505; i++) {
NSObject *objc = [[[NSObject alloc] init] autorelease];
}
_objc_autoreleasePoolPrint();
}
return 0;
}
-------------------------
objc[1804]: ##############
objc[1804]: AUTORELEASE POOLS for thread 0x1000ebe00
objc[1804]: 506 releases pending.
objc[1804]: [0x10200c000] ................ PAGE (full) (cold)
objc[1804]: [0x10200c038] ################ POOL 0x10200c038
objc[1804]: [0x10200c040] 0x100638420 NSObject
objc[1804]: [0x10200c048] 0x100637a40 NSObject
objc[1804]: [0x10200c050] 0x100636970 NSObject
...
objc[1804]: [0x100809000] ................ PAGE (hot)
objc[1804]: [0x100809038] 0x10063a0b0 NSObject
objc[1804]: ##############
- 将
505
个NSObject
对象循环加入自动释放池,当存储504
个对象时,池页已满。第505
个对象创建新池页存储 - 一页的容量:
504 * 8 = 4032
,加上56字节
成员变量和8字节
哨兵对象,共计4096
字节 - 每一页都存在
56字节
的成员变量 - 一个自动释放池,只会压栈一个哨兵对象 在源码中查看
class AutoreleasePoolPage : private AutoreleasePoolPageData
{
friend struct thread_data_t;
public:
static size_t const SIZE =
#if PROTECT_AUTORELEASEPOOL
PAGE_MAX_SIZE; // must be multiple of vm page size
#else
PAGE_MIN_SIZE; // size and alignment, power of 2
#endif
...
}
来到PAGE_MIN_SIZE
的定义
#define PAGE_MIN_SHIFT 12
#define PAGE_MIN_SIZE (1 << PAGE_MIN_SHIFT)
1 左移12
位,相当于2 ^ 12 = 4096