底层探索--内存管理的本质

2021-10-15  本文已影响0人  永断阎罗

定时器

1. CADisplayLink、NSTimer使用注意

2. GCD自定义定时器

//创建线程
dispatch_queue_t queue =  dispatch_get_global_queue(0, 0);
//初始化定时器
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//设置时间(参数-1.资源本身,2.开始时间,3.间隔时间,4.偏差,默认为0)
//开始时间:dispatch_time(DISPATCH_TIME_NOW, (2*NSEC_PER_SEC))从现在开始,2秒后执行
dispatch_source_set_timer(source, 0, (ti*NSEC_PER_SEC), 0);
//设置回调
dispatch_source_set_event_handler(source, ^{
    //处理逻辑。。。
});
//启动定时器
dispatch_resume(source);

iOS程序的内存布局

多线程的iOS程序的内存布局.png

Tagged Pointer详解

参考链接

// objc-internal.h 
static inline bool 
// 判断是否是TaggedPointer的指针
_objc_isTaggedPointer(const void * _Nullable ptr)
{
    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}

#if (TARGET_OS_OSX || TARGET_OS_IOSMAC) && __x86_64__
    // 64-bit Mac - tag bit is LSB
#   define OBJC_MSB_TAGGED_POINTERS 0  // MacOS
#else
    // Everything else - tag bit is MSB
#   define OBJC_MSB_TAGGED_POINTERS 1  // iOS
#endif

#if OBJC_MSB_TAGGED_POINTERS
#   define _OBJC_TAG_MASK (1UL<<63)  // _OBJC_TAG_MASK -- iOS
#else
#   define _OBJC_TAG_MASK 1UL       // _OBJC_TAG_MASK -- MacOS
#endif
    //经典题目:加锁、原子、同步、串行解决
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue, ^{
            self.name = [NSString stringWithFormat:@"abcdefghij"]; //崩溃,因为同时访问,name的setter方法先release后retain,可能遇到两次都release造成过度释放而访问野指针
            //self.name = [NSString stringWithFormat:@"abcdefghi"]; //为Tagged Pointer,相当于直接赋值,不是一个真正的OC对象,不会调用setter方法进行
        });
    }
    
    - (void)setName:(NSString *)name {
        if(_name != name) { 
            [_name release];
            _name = [name retain]; // or [name copy]
        }
    }

MRC的对象的setter方法

重点:使用MRC,记住原则:“谁创建谁释放”

// getter方法直接返回
- (NSString *)name {
    return _name;
}

// setter 方法
- (void)setName:(NSString *)name {
    if(_name != name) {  //保证同一个对象不用重复操作
        [_name release]; //保证替换的上一个对象计数器-1
        _name = [name retain]; // or [name copy] //计数器+1,保证此对象被当前对象拥有,即使外面对象计数器减一,此对象也不会被释放
    }
}

拷贝Copy和mutableCopy

引用计数器

    void *objc_destructInstance(id obj) 
    {
        if (obj) {
            // Read all of the flags at once for performance.
            bool cxx = obj->hasCxxDtor(); //是否有C++的析构函数
            bool assoc = obj->hasAssociatedObjects(); //是否有设置关联对象
    
            // This order is important.
            if (cxx) object_cxxDestruct(obj); //清楚成员变量
            if (assoc) _object_remove_assocations(obj); //移除关联对象
            obj->clearDeallocating(); //将指向当前对象的弱指针置为nil
        }
    
        return obj;
    }

自动释放池

主线程的自动释放池

//重新编译为C/C++ 文件后的源码
struct __AtAutoreleasePool {
    __AtAutoreleasePool() { //构造函数
        atautoreleasepoolobj = objc_autoreleasePoolPush(); //运行时的放入函数
    }
    ~__AtAutoreleasePool() { //析构函数
        objc_autoreleasePoolPop(atautoreleasepoolobj); //运行时的释放函数
    }
    void * atautoreleasepoolobj;
};

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    // @autoreleasepool
    { __AtAutoreleasePool __autoreleasepool;

        appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));
    }
    return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}
    class AutoreleasePoolPage;
    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;
    
        AutoreleasePoolPageData(__unsafe_unretained id* _next, pthread_t _thread, AutoreleasePoolPage* _parent, uint32_t _depth, uint32_t _hiwat)
            : magic(), next(_next), thread(_thread),
              parent(_parent), child(nil),
              depth(_depth), hiwat(_hiwat)
        {
        }
    };
    
    //底层push函数-向RunloopPage里加入对象
    static inline void *push() 
    {
        id *dest;
        if (slowpath(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;
    }
    
    //底层pop函数-释放RunloopPage里的对象
    static inline void pop(void *token)
    {
        AutoreleasePoolPage *page;
        id *stop;
        if (token == (void*)EMPTY_POOL_PLACEHOLDER) {
            // Popping the top-level placeholder pool.
            page = hotPage();
            if (!page) {
                // Pool was never used. Clear the placeholder.
                return setHotPage(nil);
            }
            // Pool was used. Pop its contents normally.
            // Pool pages remain allocated for re-use as usual.
            page = coldPage();
            token = page->begin();
        } else {
            page = pageForPointer(token);
        }
    
        stop = (id *)token;
        if (*stop != POOL_BOUNDARY) {
            if (stop == page->begin()  &&  !page->parent) {
                // Start of coldest page may correctly not be POOL_BOUNDARY:
                // 1. top-level pool is popped, leaving the cold page in place
                // 2. an object is autoreleased with no pool
            } else {
                // Error. For bincompat purposes this is not 
                // fatal in executables built with old SDKs.
                return badPop(token);
            }
        }
    
        if (slowpath(PrintPoolHiwat || DebugPoolAllocation || DebugMissingPools)) {
            return popPageDebug(token, page, stop);
        }
    
        return popPage<false>(token, page, stop);
    }

ARC下的自动内存管理机制(结合上面的进行理解)

上一篇 下一篇

猜你喜欢

热点阅读