1. 数据结构
// AutoreleasePoolPage对象
class AutoreleasePoolPage
{
static pthread_key_t const key = AUTORELEASE_POOL_KEY;
magic_t const magic;
id *next; // 自动回收对象栈的栈指针(相当于sp)
pthread_t const thread; // 当前回收迟对应的线程
AutoreleasePoolPage * const parent;// parent页指针 链表指针
AutoreleasePoolPage *child; // child页指针 链表指针
}
-
parent和child使AutoreleasePoolPage对象组成一个双向链表
双向链表 - 栈(存储autorelease对象指针)
AutoreleasePoolPage ->
id *next; // 相当于栈指针sp
// 看add方法
id *add(id obj)
{
//assert(!full());
// unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
// protect();
return ret;
}
- 游标 hotPage()获取当前线程的当前AutoreleasePoolPage页
// 获取当前线程的hotPage
static inline AutoreleasePoolPage *hotPage()
{
AutoreleasePoolPage *result = (AutoreleasePoolPage *)
tls_get_direct(key);
if (result) result->fastcheck();
return result;
}
// 设置当前线程的hotPage
static inline void setHotPage(AutoreleasePoolPage *page)
{
if (page) page->fastcheck();
tls_set_direct(key, (void *)page);
}
- POOL_SENTINEL哨兵
#define POOL_SENTINEL nil // POOL_SENTINEL 这个很重要,是自动回收池栈帧的分隔符
备注:TLS(线程独享存储技术)
TSL的存储是每个线程独立的,互不干扰。
TLS是线程局部存储(Thread Local Storage)的缩写,在oc中通过这两个方法来使用:
static inline void *tls_get_direct(tls_key_t k)
{
assert(is_valid_direct_key(k));
if (_pthread_has_direct_tsd()) {
return _pthread_getspecific_direct(k);
} else {
return pthread_getspecific(k);
}
}
static inline void tls_set_direct(tls_key_t k, void *value)
{
assert(is_valid_direct_key(k));
if (_pthread_has_direct_tsd()) {
_pthread_setspecific_direct(k, value);
} else {
pthread_setspecific(k, value);
}
}
2.调用
// @autoreleasepool {}
相当于 -->
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
}
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
相当于 -->
void * atautoreleasepoolobj = objc_autoreleasePoolPush();
// do whatever you want
objc_autoreleasePoolPop(atautoreleasepoolobj);
//
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt); // 执行所有autorelease对象的release
}
对象调用autorelease的过程
[obj autorelease] 相当于 --> AutoreleasePoolPage::autorelease(obj);
//
static inline id autorelease(id obj)
{
id *dest __unused = autoreleaseFast(obj);
}
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj); // 添加对象指针到当前页的栈
} else if (page) {
return autoreleaseFullPage(obj, page); // 创建新的AutoreleasePoolPage,并add
} else {
return autoreleaseNoPage(obj); // 创建根AutoreleasePoolPage并add
}
}
///// autoreleaseNoPage
id *autoreleaseNoPage(id obj)
{
// No pool in place.
assert(!hotPage());
if (obj != POOL_SENTINEL && DebugMissingPools) {
// We are pushing an object with no pool in place,
// and no-pool debugging was requested by environment.
_objc_inform("MISSING POOLS: Object %p of class %s "
"autoreleased with no pool in place - "
"just leaking - break on "
"objc_autoreleaseNoPool() to debug",
(void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
// Install the first page.
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push an autorelease pool boundary if it wasn't already requested.
if (obj != POOL_SENTINEL) {
page->add(POOL_SENTINEL);
}
// Push the requested object.
return page->add(obj);
}
push和pop
static inline void *push()
{
id *dest;
if (DebugPoolAllocation) {
// Each autorelease pool starts on a new pool page.
dest = autoreleaseNewPage(POOL_SENTINEL);
} else {
dest = autoreleaseFast(POOL_SENTINEL);
}
assert(*dest == POOL_SENTINEL);
return dest;
}
static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop;
page = pageForPointer(token);
stop = (id *)token;
if (DebugPoolAllocation && *stop != POOL_SENTINEL) {
// This check is not valid with DebugPoolAllocation off
// after an autorelease with a pool page but no pool in place.
_objc_fatal("invalid or prematurely-freed autorelease pool %p; ",
token);
}
if (PrintPoolHiwat) printHiwat();
page->releaseUntil(stop);
// memory: delete empty children
if (DebugPoolAllocation && page->empty()) {
// special case: delete everything during page-per-pool debugging
AutoreleasePoolPage *parent = page->parent;
page->kill();
setHotPage(parent);
} else if (DebugMissingPools && page->empty() && !page->parent) {
// special case: delete everything for pop(top)
// when debugging missing autorelease pools
page->kill();
setHotPage(nil);
}
else if (page->child) {
// hysteresis: keep one empty child if page is more than half full
if (page->lessThanHalfFull()) {
page->child->kill();
}
else if (page->child->child) {
page->child->child->kill();
}
}
}
关键字
双向链表, TLS(线程独享存储), 分页的栈, 哨兵
网友评论