学习autorelease

开发者 2024-10-6 14:04:21 20 0 来自 中国
关于@ autoreleasepool{}

在main方法中有一个@autoreleasepool{}
int main(int argc, char * argv[]) {    NSString * appDelegateClassName;    @autoreleasepool {        // Setup code that might create autoreleased objects goes here.        appDelegateClassName = NSStringFromClass([AppDelegate class]);    }    return UIApplicationMain(argc, argv, nil, appDelegateClassName);}@autoreleasePool{} 的底层是一个__AtAutoreleasepool结构体,这个结构体在初始化时调用objc_autoreleasePoolPush(), 析构方法时调用objc_autoreleasePoolPop()方法。
struct __AtAutoreleasePool {  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}  void * atautoreleasepoolobj;};Autoreleasepool原理

void *objc_autoreleasePoolPush(void) {    return AutoreleasePoolPage::push();}void objc_autoreleasePoolPop(void *ctxt) {    AutoreleasePoolPage::pop(ctxt);}由以上代码可看出,调用push和pop方法实在调用的是AutoreleasePoolPage的push和pop方法
AutoreleasePoolPage

AutoreleasePoolPage的数据结构如下:
class AutoreleasePoolPage {    magic_t const magic;    id *next;    pthread_t const thread;    AutoreleasePoolPage * const parent;    AutoreleasePoolPage *child;    uint32_t const depth;    uint32_t hiwat;};

  • magic 判断autoreleasePoolPage的完备性,获取当前page时用
  • next    指向下一个对象
  • thread   当前page地点的线程
  • parent/child 双向链表的指针
自动开释池中AutoreleasePoolPage是用双向链表毗连起来的,parent/child 是构造双向链表的指针
AutoreleasePoolPage的栈结构如图:


栈中包罗begin()/end()方法,获取存取对象的开始、竣事地点。
next指向的是下一个对象
栈顶有一个POOL_SENTINEL哨兵对象,值为nil
#define POOL_SENTINEL nilPush()

void *objc_autoreleasePoolPush(void) {    return AutoreleasePoolPage::push();}AutoreleasePoolPage内的push方法
static inline void *push() {   return autoreleaseFast(POOL_SENTINEL);}主要调用的方法是autoreleaseFast
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);   }}hotPage()指的是当前pape,由代码所示:

  • 如果page不满时,直接在page中添加对象;
  • 如果page满了,会调用autoreleaseFullPage方法,遍历双向链表,找到一个未满的page,设置为hotpage,然后在page中添加对象。
  • 如果page不存在,调用autoreleaseNoPage方法,新建一个AutoreleasePoolPage对象,设置为hot Page,然后在栈顶添加哨兵对象。
add方法,实在就是压栈操作
id *add(id obj) {    id *ret = next;    *next = obj;    next++;    return ret;}Pop()

void objc_autoreleasePoolPop(void *ctxt) {    AutoreleasePoolPage::pop(ctxt);}这个方法一样平常传参是哨兵对象,但是不传哨兵对象也可以。
static inline void pop(void *token) {    AutoreleasePoolPage *page = pageForPointer(token);    id *stop = (id *)token;    page->releaseUntil(stop);    if (page->child) {        if (page->lessThanHalfFull()) {            page->child->kill();        } else if (page->child->child) {            page->child->child->kill();        }    }}

  • 先调用pageForPointer方法查找当前page,pageForPointer是将指针与页面巨细(4096)取模,得到当前指针的偏移量
  • releaseUntil方法,release对象
  • 调用child的kill方法删除当前页和子页
autorelease()

inline id objc_object::rootAutorelease() {   if (isTaggedPointer()) return (id)this;   if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;   return rootAutorelease2();}__attribute__((noinline,used)) id objc_object::rootAutorelease2() {   return AutoreleasePoolPage::autorelease((id)this);}static inline id autorelease(id obj) {  id *dest __unused = autoreleaseFast(obj);  return obj;}autorelease方法实在调用的autoreleaseFast 方法,添加对象
Autorelease对象什么时间开释?

runloop中每次迭代会自动参加自动开释池的push和pop,以是Autorelease对象是在runloop迭代竣事后开释的。
runloop和autoreleasepool的关系

App启动后,苹果在主线程RunLoop里注册了两个Observe,其回调都是_wrapRunLoopWithAutoReleasePoolHandler()。
第一个Observer监听的时间是Entry(即将进入Loop),其回调内会调用_objc_autoreleasePoolPush()创建自动开释池。优先级最高,包管创建开释池发生在其他全部回调之前。
第二个Observer监听了两个变乱:BeforeWaiting(预备进入休眠)调用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()开释旧池并创建新池;Exit(即将退出Loop)是调用_objc_autoreleasePoolPop()来开释自动开释池。优先级最低,包管其开释池发生在其他全部回到之后。
主线程实验的代码,通常是写在诸如变乱回调、Timer回调内的。这些回调被RunLoop创建好的AutoreleasePool围绕着,以是不会出现内存走漏,开发者也不必表现创建Pool。
参考链接:
自动开释池的宿世今生
内幕背后的autorelease
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 16:50, Processed in 0.123008 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表