AutoReleasePool

一、autoreleasepool源码解释

AutoreleasePool是一个堆栈,里面装着指针。那么栈的底层实现是什么呢?是数组。

AutoreleasePool全名叫NSAutoreleasePool。它就是一个对象引用计数自动处理器,在官方文档中被称为是一个类。

在ARC中,在遵守一些规则的情况下,可以自动释放对象。系统自动帮对象调用了autorelease方法,然后就会把对象扔进池里面,等一次runloop结束,这个池会被系统销毁,池里面的对象也就跟着被销毁了。


NSAutoreleasePool可以同时有多个,它的组织是个栈,总是存在一个栈顶pool,也就是当前pool,每创建一个pool,就往栈里压一个,改变当前pool为新建的pool,然后,每次给pool发送drain消息,就弹出栈顶的pool,改当前pool为栈里的下一个 pool。


跟MRC的release方法比较就是延迟了对象的销毁的时间。但autoreleasepool依然不是.Net/Java那种全自动的垃圾回收机制。






二、@autoreleasepool{} C++文件

@autoreleasepool 到底是什么?我们在命令行中使用 clang -rewrite-objc main.m 让编译器重新改写这个文件。

如果报错'UIKit/UIKit.h' file not found ,解决方法如下:

1.进入终端,键入命令 vim ~/.bash_profile 

2.在vim界面输入i进入编辑编辑状态并且键入:alias rewriteoc='clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk' 


3.键入完毕,点esc退出编辑状态,再键入:wq退出vim并保存,执行source ~/.bash_profile<-这句一定要执行,执行才会生效


clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk xxxxx.m


请参考:https://www.jianshu.com/p/43a09727eb2c


编译到的main.cpp文件主要代码如下:

/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool}; 

@autoreleasepool是一个_AtAutoreleasePool的结构体。_AtAutoreleasePool的结构体里的方法如下:
struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

autoreleasepool里是调用 栈结构的push() 和 pop() 操作。


三、autoreleasepool结构

综上两点得出autoreleasepool结构如下图:


autoreleasepool底层是由autoreleasepoolpage组成的双向链表结构。


四、autoreleasepoolpage组成


  magic_t const magic; //用来校验 AutoreleasePoolPage 的结构是否完整

  id *next;//指向最新添加的 autoreleased 对象的下一个位置,初始化时指向 begin() 

  pthread_t const thread;//指向当前线程

  AutoreleasePoolPage * const parent;// 指向父结点,第一个结点的 parent 值为 nil 

  AutoreleasePoolPage *child;//指向父结点,第一个结点的 parent 值为 nil 

  uint32_t const depth;//链表的深度,节点个数

  uint32_t hiwat;//high water mark 数据容纳的一个上限

  PAGE_MAX_SIZE;//size大小为4096,虚拟内存每个扇区4096个字节,4K对齐的说法

  COUNT;//一个page里的对象数

  POOL_BOUNDARY;//边界对象,以前为POOL_SENTINEL哨兵对象

五、autoreleasepool 运行过程

主要过程:

AutoreleasePoolPage::push()

AutoreleasePoolPage::autorelease((id)this);

AutoreleasePoolPage::pop(ctxt)


源码代码示例:

——————— push —————— 
void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}


 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;
    }



 static inline id *autoreleaseFast(id obj)
    {
        AutoreleasePoolPage *page = hotPage();//coldpage()
        if (page && !page->full()) {
            return page->add(obj);
        } else if (page) {
            return autoreleaseFullPage(obj, page);
        } else {
            return autoreleaseNoPage(obj);//完全没有page,重新创建一个page,并把对象加入page中
        }
    }


id *add(id obj)
    {
        id *ret = next;  // faster than `return next-1` because of aliasing
        *next ++ = obj;
        return ret;
    }




—————— autorelease ——————
// Replaced by ObjectAlloc
- (id)autorelease {
    return ((id)self)->rootAutorelease();
}

__attribute__((noinline,used))
id 
objc_object::rootAutorelease2()
{
    assert(!isTaggedPointer());
    return AutoreleasePoolPage::autorelease((id)this);
}


static inline id autorelease(id obj)
    {
        id *dest __unused = autoreleaseFast(obj);
        assert(!dest  ||  dest == EMPTY_POOL_PLACEHOLDER  ||  *dest    == obj);
        return obj;
    }


autoreleaseFast()





——————— pop ——————   
void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}


static inline void pop(void *token) 
    {
        AutoreleasePoolPage *page;
        id *stop;
  	 page = pageForPointer(token);
        stop = (id *)token;
	page->releaseUntil(stop);

}

void releaseUntil(id *stop) 
{
 while (this->next != stop) {
  	AutoreleasePoolPage *page = hotPage();
	id obj = *--page->next;
 	if (obj != POOL_BOUNDARY) {
          objc_release(obj);
      }
  }
}

__attribute__((aligned(16)))
void 
objc_release(id obj)
{
    if (!obj) return;
    if (obj->isTaggedPointer()) return;
    return obj->release();
}

inline void
objc_object::release()
{
    assert(!isTaggedPointer());

    if (fastpath(!ISA()->hasCustomRR())) {
        rootRelease();
        return;
    }

    ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_release);
}


六、验证

1.下载源码

2.查看验证page的内容。在源码的main.m里输入一个字符串,打上断点:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString * s1 = [NSString stringWithFormat:@"8pmedu28pmedu28pmedu--S1"];
    }
    return 0;
}

3.在源码main.m里使用以下命令,查看当前page页内容

expr AutoreleasePoolPage::hotPage()

(lldb)  expr AutoreleasePoolPage::hotPage()
((anonymous namespace)::AutoreleasePoolPage *) $1 = 0x0000000102803000

  p *$1

p *$1
((anonymous namespace)::AutoreleasePoolPage) $2 = {
  magic = {
    m = ([0] = 2711724449, [1] = 1330926913, [2] = 1162626386, [3] = 558191425)
  }
  next = 0x0000000102803048
  thread = 0x00000001009ba380
  parent = 0x0000000000000000
  child = 0x0000000000000000
  depth = 0
  hiwat = 0
}

p $1.printAll()

(lldb)  p $1.printAll()
objc[1756]: ##############
objc[1756]: AUTORELEASE POOLS for thread 0x1009ba380
objc[1756]: 2 releases pending.
objc[1756]: [0x102803000]  ................  PAGE  (hot) (cold)
objc[1756]: [0x102803038]  ################  POOL 0x102803038
objc[1756]: [0x102803040]       0x100c37fc0  __NSCFString
objc[1756]: ##############
  Fix-it applied, fixed expression was: 
    $1->printAll()

验证   POOL 0x102803038的内存地址a.打印出next[-1]  pool_boundary所在的值

p $0.next[-2]

(id) $11 = nil
  Fix-it applied, fixed expression was: 
    $0->next[-2]
b.取地址符

p &$11

(id *) $12 = 0x000000010100a038

c.比较b的结果和p $1.printAll()里POOL 的地址值。



猜你喜欢

转载自blog.csdn.net/sunnysu99/article/details/80227912