一、先创建一个Dog
类,重写dealloc
方法,看看Dog
类的实例什么时候释放。工程改为MRC 工程:
发现实例并没有释放,在MRC 下需要添加 autorelease
或则 release
二、c++ 重写 main.m
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m -o main-arm64.cpp
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
Dog *g = ((Dog *(*)(id, SEL))(void *)objc_msgSend)((id)((Dog *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Dog"), sel_registerName("alloc")), sel_registerName("init"));
}
return 0;
}
struct __AtAutoreleasePool {
__AtAutoreleasePool() {//构造函数,在创建结构体时调用
atautoreleasepoolobj = objc_autoreleasePoolPush();
}
~__AtAutoreleasePool() {//析构函数,在销毁结构体时调用
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
void * atautoreleasepoolobj;
};
1.__AtAutoreleasePool() { atautoreleasepoolobj = objc_autoreleasePoolPush(); }
:构造函数,在创建结构体时调用
2.~__AtAutoreleasePool() { objc_autoreleasePoolPop(atautoreleasepoolobj); }
:析构函数,在销毁结构体时调用
3.所以上面代码可以改为:
伪代码
{
__AtAutoreleasePool __autoreleasepool;
atautoreleasepoolobj = objc_autoreleasePoolPush();
Dog *g = [[[Dog alloc] init] autorelease];
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
__autoreleasepool
是一个局部变量,大括号结束就会调用objc_autoreleasePoolPop
,将autorelease
对象释放。
三、看源码实现
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
class AutoreleasePoolPage
{
PAGE_MAX_SIZE;
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
以上源码只保留重要部分。
704C76E6-6322-4DD3-9751-FA296AB96C79.png
1.AutoreleasePoolPage 本质是这么一个结构,大小是4096字节。(PAGE_MAX_SIZE
:4096,源码得到)。
2.前7个变量都是8字节,剩下的4040字节存储着autorelease
对象地址
3.AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
:由此可知当4040字节无法放下autorelease
对象地址时,会扩展一个AutoreleasePoolPage
,且该数据结构是,双向链表
4.next 指针指向当前
autorelease
对象地址位置,每push 一个 对象,next 就会++。
id *add(id obj)
{
assert(!full());
unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
protect();
return ret;
}
5.POOL_BOUNDARY
边界:# define POOL_BOUNDARY nil
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;
}
每次push 对象的时候会先pushPOOL_BOUNDARY
边界。
id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this));
}
id * end() {
return (id *) ((uint8_t *)this+SIZE);
}
begin:7个成员变量之后的开始位置
end:结束位置
7.releaseUntil(begin());
:release 直到 begin
hotPage()
:当前AutoreleasePoolPage
coldPage
:非当前AutoreleasePoolPage
四、runloop 、 autorelease、子线程
1.主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,并进行Push、Pop 等操作来进行内存管理。
2.子线程默认不开启runloop,当产生autorelease对象时候,会将对象添加到AutoreleasePoolPage中,也就是不手动创建Autoreleasepool也能正确释放对象,线程销毁时release对象
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 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);
}
}
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;
if (haveEmptyPoolPlaceholder()) {
// We are pushing a second pool over the empty placeholder pool
// or pushing the first object into the empty placeholder pool.
// Before doing that, push a pool boundary on behalf of the pool
// that is currently represented by the empty placeholder.
pushExtraBoundary = true;
}
else if (obj != POOL_BOUNDARY && DebugMissingPools) {
// We are pushing an object with no pool in place,
// and no-pool debugging was requested by environment.
_objc_inform("MISSING POOLS: (%p) Object %p of class %s "
"autoreleased with no pool in place - "
"just leaking - break on "
"objc_autoreleaseNoPool() to debug",
pthread_self(), (void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
else if (obj == POOL_BOUNDARY && !DebugPoolAllocation) {
// We are pushing a pool with no pool in place,
// and alloc-per-pool debugging was not requested.
// Install and return the empty pool placeholder.
return setEmptyPoolPlaceholder();
}
// 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);
}
Autoreleasepool 销毁时机也就是autorelease 对象销毁时机
网友评论