文章目录
Tips
:利用_objc_autoreleasePoolPrint()
可以查看注册到autoreleasepool
的对象,方便我们调试。
autoreleasepool
的结构是一个双向链表,分别指向parent
和child
表,一个page
表相当于一个栈结构,遵循先进后出
结构分析
AutoreleasePoolPage
打开NSObject
源码我们发现autoreleasepool
接口围绕AutoreleasePoolPage
进行调用,源码如下:
class AutoreleasePoolPage
{
// EMPTY_POOL_PLACEHOLDER is stored in TLS when exactly one pool is
// pushed and it has never contained any objects. This saves memory
// when the top level (i.e. libdispatch) pushes and pops pools but
// never uses them.
# 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;
// SIZE-sizeof(*this) bytes of contents follow
static void * operator new(size_t size) {
return malloc_zone_memalign(malloc_default_zone(), SIZE, SIZE);
}
static void operator delete(void * p) {
return free(p);
}
...... //此处略去代码
id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this));
}
id * end() {
return (id *) ((uint8_t *)this+SIZE);
}
bool empty() {
return next == begin();
}
bool full() {
return next == end();
}
bool lessThanHalfFull() {
return (next - begin() < (end() - begin()) / 2);
}
id *add(id obj)
{
assert(!full());
unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
protect();
return ret;
}
......//此处略去代码
public:
static inline id autorelease(id obj)
{
assert(obj);
assert(!obj->isTaggedPointer());
id *dest __unused = autoreleaseFast(obj);
assert(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
return obj;
}
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);
return dest;
}
magic
用来校验AutoreleasePoolPage
的结构是否完整;next
指向最新添加的autoreleased
对象的下一个位置,初始化时指向begin()
;thread
指向当前线程;parent
指向父结点,第一个结点的parent
值为nil
;child
指向子结点,最后一个结点的child
值为nil
;depth
代表深度,从0
开始,往后递增1
;hiwat
代表high water mark
。- 分配的内存大小
PAGE_MAX_SIZE
为4096
,即虚拟内存一页大小 obj->isTaggedPointer()
表示Tagged Pointer
对象不能加入autoreleasepool
另外,当next == begin()
时,表示AutoreleasePoolPage
为空;当next == end()
时,表示AutoreleasePoolPage
已满。
创建函数
由源码可知,由push
操作创建一个新的AutoreleasePoolPage
,看下创建函数
AutoreleasePoolPage(AutoreleasePoolPage *newParent)
: magic(), next(begin()), thread(pthread_self()),
parent(newParent), child(nil)<