AutoReleasePool 工作机制

AutoReleasePool 工作机制

背景:

相比很多人都有这个困惑,@autoreleasepool 到底做了什么,今天我们就从源码的基础上去分析,彻底揭开它神秘面纱

源码路径:

https://opensource.apple.com/tarballs/objc4/

得益于objc 开源,我们可以一窥其本质,在接下来分析中我会尽可能引入源码

@autoreleasepool 转成c++到底是什么样的

Objective-C
  @autoreleasepool
    {

        NSObject *pObjecdt = nil;
        pObjecdt = [[Test alloc] init];
        [pObjecdt autorelease];
        NSLog(@"refcount = %d", CFGetRetainCount(pObjecdt));
    }

OC C++

 使用命令

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp

就可以把对对应m 转成c++

Objective-C
 {
         __AtAutoreleasePool __autoreleasepool;

        NSObject *pObjecdt = __null;
        pObjecdt = ((Test *(*)(id, SEL))(void *)objc_msgSend)((id)((Test *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Test"), sel_registerName("alloc")), sel_registerName("init"));
        ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)pObjecdt, sel_registerName("autorelease"));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_x4_q4k0pbd17n90b9x6_v_h_rb40000gn_T_main_092efe_mi_0, CFGetRetainCount(pObjecdt));
    }

也就是说@autoreleasepool 转换成了__AtAutoreleasePool __autoreleasepool;

下边就介绍__AtAutoreleasePool的定义

__AtAutoreleasePool

C++
struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

通过上边可以看的出来 这是很简单的结构图,遵循的RAII的原则,也就是说构造的时候生成atautoreleasepoolobj 指针,而 西沟的时候把atautoreleasepoolobj 传入到objc_autoreleasePoolPop中去,所以要搞清楚AutoReleasePool 就要搞清楚objc_autoreleasePoolPush 与 objc_autoreleasePoolPop 是干啥的。

objc_autoreleasePoolPush

C++
struct AutoreleasePoolPageData
{
        magic_t const magic;
        __unsafe_unretained id *next;
        pthread_t const thread;
        AutoreleasePoolPage * const parent;
        AutoreleasePoolPage *child;
        uint32_t const depth;
        uint32_t hiwat;
};

class AutoreleasePoolPage : private AutoreleasePoolPageData
{
}

void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}
#   define POOL_BOUNDARY nil

    static inline void *push()
    {
        id *dest;
        dest = autoreleaseFast(POOL_BOUNDARY);
        return dest;
    }
        //obj = POOL_BOUNDARY
       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 inline AutoreleasePoolPage *hotPage()
            {
                AutoreleasePoolPage *result = (AutoreleasePoolPage *)
                    tls_get_direct(key);
                if ((id *)result == EMPTY_POOL_PLACEHOLDER) return nil;
                if (result) result->fastcheck();
                return result;
            }
            class AutoreleasePoolPage
            {
                //obj = POOL_BOUNDARY
                id *add(id obj)
                {
           
                    id *ret;
           
             
                    ret = next;  // faster than `return next-1` because of aliasing
                    *next++ = obj;
           
                    return ret;
                }
            }
       

通过上边调用关系可以看的出来,AutoreleasePoolPage 是跟线程相关的,push首先从tls 中取出当前线程相关连的AutoreleasePoolPage指针,类似于opengl context的原理,把POOL_BOUNDARY 放入到AutoreleasePoolPage的next位置的地方


objc_autoreleasePoolPop

C++
void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}
    void AutoreleasePoolPage::pop(void *token)
    {
        AutoreleasePoolPage *page;
        id *stop;
      
        return popPage<false>(token, page, stop);
    }
   
     template<bool allowDebug>
    static void
    popPage(void *token, AutoreleasePoolPage *page, id *stop)
    {
        page->releaseUntil(stop);
     }

    //stop 最接近的一个POOL_BOUNDARY 的地址
    void releaseUntil(id *stop)
    {
        // Not recursive: we don't want to blow out the stack
        // if a thread accumulates a stupendous amount of garbage
       
        while (this->next != stop) {
            // Restart from hotPage() every time, in case -release
            // autoreleased more objects
            AutoreleasePoolPage *page = hotPage();

            id obj = *--page->next;

            if (obj != POOL_BOUNDARY) {
                objc_release(obj);
            }
        }
    }
    void
    objc_release(id obj)
    {
        if (obj->isTaggedPointerOrNil()) return;
        return obj->release();
    }
   
            inline void
        objc_object::release()
        {
            ASSERT(!isTaggedPointer());
       
            rootRelease(true, RRVariant::FastOrMsgSend);
        }
       
       
        ALWAYS_INLINE bool
        objc_object::rootRelease()
        {
            return rootRelease(true, RRVariant::Fast);
        }
        bool
        objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
        {
            

            // don't check newisa.fast_rr; we already called any RR overrides
            uintptr_t carry;
            newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--
            //#define slowpath(x) (__builtin_expect(bool(x), 0))
            //    __builtin_expect((x),1)表示 x 的值为真的可能性更大;
            //bool isDeallocating() {
            //  return extra_rc == 0;
   
            if (slowpath(newisa.isDeallocating()))
                goto deallocate;
             return false;
         deallocate:
           if (performDealloc) {
                ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
            }
         }

Autorelease 源码解析

[pObjecdt autorelease];

也就是看下这个里边到底在干什么

C++
// Replaced by ObjectAlloc
- (id)autorelease {
    return _objc_rootAutorelease(self);
}
    id _objc_rootAutorelease(id obj)
    {
        ASSERT(obj);
        return obj->rootAutorelease();
    }
        inline id objc_object::rootAutorelease()
        {
            if (isTaggedPointer()) return (id)this;
           
            return rootAutorelease2();
        }
            id objc_object::rootAutorelease2()
            {
                ASSERT(!isTaggedPointer());
                return AutoreleasePoolPage::autorelease((id)this);
            }
           
                static inline id AutoreleasePoolPage::autorelease(id obj)
                {
                    id *dest __unused = autoreleaseFast(obj);
                    return obj;
                }
                    static inline id *AutoreleasePoolPage::autoreleaseFast(id obj)
                    {
                      //这里就跟PoolPush 方法调用逻辑是一样的了,就把这个指针入到page页面里面
                    }

经过上边分析,我们看下边代码情景会生发生什么

Case 1:

Objective-C
    NSObject *pObjecdt = nil;
    @autoreleasepool
    {
        pObjecdt = [[Test alloc] init];
        [pObjecdt autorelease];
        NSLog(@"refcount = %d", CFGetRetainCount(pObjecdt));
    }
    NSLog(@"refcount = %d", CFGetRetainCount(pObjecdt));
   

Case 2:

Objective-C
    @autoreleasepool {
        NSObject *pObjecdt1 = [[[Test alloc] init] retain];
        @autoreleasepool
        {

            NSObject *pObjecdt = [[Test alloc] init];
            [pObjecdt autorelease];
            _objc_autoreleasePoolPrint();
        }
    }

相关源码

Objective-C
#ifndef Test_h
#define Test_h

@interface Test : NSObject
{
   
}
-(void)dealloc;
+ (NSString *)description;
@end
#endif /* Test_h */


 

Objective-C

#import <Foundation/Foundation.h>
#import "Test.h"
@implementation Test
-(void)dealloc
{
    NSLog(@"Test Destory!");
}
+ (NSString *)description
{
    return @"Test";
}
@end

总结:

也就是auto release pool 只有调用对象调用 auto release才会起作用,如果没有,可以忽略这个auto release pool

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值