Objective-C

iOS:内存管理进阶篇

2020-05-18  本文已影响0人  码小菜
风景

目录
一,引用计数的存储
二,weak指针的存储
三,autoreleasepool的原理
四,autoreleasepool和runloop的关系

一,引用计数的存储

1,isa共用体(源码下载地址

struct objc_object {
    isa_t isa;
};

union isa_t {
    uintptr_t bits;
    struct {
    # if __arm64_ // iOS平台
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33;
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19
    # elif __x86_64__ // Mac平台
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 44;
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 8
    #endif
    };
};

2,SideTable结构体

struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts; // 存储引用计数的散列表
    weak_table_t weak_table;
};

3,说明

4,底层代码

inline uintptr_t 
objc_object::rootRetainCount()
{
    if (isTaggedPointer()) return (uintptr_t)this;

    sidetable_lock();
    isa_t bits = LoadExclusive(&isa.bits);
    ClearExclusive(&isa.bits);
    
    // 如果是共用体
    if (bits.nonpointer) {
        // 从extra_rc中取出引用计数
        uintptr_t rc = 1 + bits.extra_rc;
        // 如果存储在SideTable中
        if (bits.has_sidetable_rc) {
            // 从SideTable中取出引用计数
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    return sidetable_retainCount();
}

size_t 
objc_object::sidetable_getExtraRC_nolock()
{
    assert(isa.nonpointer);
    // 取出SideTable
    SideTable& table = SideTables()[this];
    // 从refcnts中取出引用计数
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) return 0;
    else return it->second >> SIDE_TABLE_RC_SHIFT;
}
// 简化代码
ALWAYS_INLINE id
objc_object::rootRetain(bool tryRetain, bool handleOverflow)
{
    if (isTaggedPointer()) return (id)this;

    do {
        transcribeToSideTable = false;
        oldisa = LoadExclusive(&isa.bits);
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
            if (!tryRetain && sideTableLocked) sidetable_unlock();
            if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
            // SideTable执行retain
            else return sidetable_retain();
        }
        uintptr_t carry;
        // extra_rc中的值+1
        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++
    } while (slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)));

    if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
    return (id)this;
}

id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    // 取出SideTable
    SideTable& table = SideTables()[this];
    
    table.lock();
    // 从refcnts中取出引用计数
    size_t& refcntStorage = table.refcnts[this];
    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
        // 引用计数+1
        refcntStorage += SIDE_TABLE_RC_ONE;
    }
    table.unlock();

    return (id)this;
}
// 简化代码
ALWAYS_INLINE bool
objc_object::rootRelease(bool performDealloc, bool handleUnderflow)
{
    if (isTaggedPointer()) return false;
    
    do {
        oldisa = LoadExclusive(&isa.bits);
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
            if (sideTableLocked) sidetable_unlock();
            // SideTable执行release
            return sidetable_release(performDealloc);
        }
        uintptr_t carry;
        // extra_rc中的值-1
        newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--
        if (slowpath(carry)) {
            goto underflow;
        }
    } while (slowpath(!StoreReleaseExclusive(&isa.bits,
                                             oldisa.bits, newisa.bits)));
    
    if (slowpath(sideTableLocked)) sidetable_unlock();
    return false;
}

uintptr_t
objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    // 取出SideTable
    SideTable& table = SideTables()[this];

    bool do_dealloc = false;

    table.lock();
    // 从refcnts中取出引用计数
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) {
        do_dealloc = true;
        table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
    } else if (it->second < SIDE_TABLE_DEALLOCATING) {
        do_dealloc = true;
        it->second |= SIDE_TABLE_DEALLOCATING;
    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
        // 引用计数-1
        it->second -= SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    // 如果引用计数为0
    if (do_dealloc  &&  performDealloc) {
        // 销毁对象
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
    }
    return do_dealloc;
}
二,weak指针的存储
1,底层结构
struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts; 
    weak_table_t weak_table; // 存储weak指针的散列表
};

struct weak_table_t {
    weak_entry_t *weak_entries;      // weak_entry_t数组
    size_t    num_entries;           // 数组元素个数
    uintptr_t mask;                  // 数组长度 - 1
    uintptr_t max_hash_displacement; // 最大位移次数
};

// 优先使用静态数组存储,超过4个再使用动态数组存储
#define WEAK_INLINE_COUNT 4 // 静态数组的长度
struct weak_entry_t {
    DisguisedPtr<objc_object> referent; // 对象
    union {
        struct {
            weak_referrer_t *referrers;              // weak_referrer_t动态数组
            uintptr_t        out_of_line_ness : 2;   // 标识数组是否已创建
            uintptr_t        num_refs : PTR_MINUS_2; // 数组元素个数
            uintptr_t        mask;                   // 数组长度 - 1
            uintptr_t        max_hash_displacement;  // 最大位移次数
        };
        struct {
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT]; // weak_referrer_t静态数组
        };
    };
};
底层结构
2,存储
// 简化代码
id
weak_register_no_lock(weak_table_t *weak_table, id referent_id,
                      id *referrer_id, bool crashIfDeallocating)
{
    // 对象
    objc_object *referent = (objc_object *)referent_id;
    // weak指针
    objc_object **referrer = (objc_object **)referrer_id;

    // 在weak_table的weak_entries中查找对象所在的weak_entry_t
    weak_entry_t *entry;
    if ((entry = weak_entry_for_referent(weak_table, referent))) { // 已找到
        // 将weak指针存储到weak_entry_t的数组中
        append_referrer(entry, referrer);
    }
    else { // 未找到(第一次存储)
        // 用对象和weak指针新建一个weak_entry_t
        weak_entry_t new_entry(referent, referrer);
        // 查看weak_table是否需要扩容
        weak_grow_maybe(weak_table);
        // 将新建的weak_entry_t存储到weak_table的weak_entries中
        weak_entry_insert(weak_table, &new_entry);
    }

    return referent_id;
}
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
    assert(referent);
    weak_entry_t *weak_entries = weak_table->weak_entries;
    if (!weak_entries) return nil;

    // 索引 = 对象 & mask
    size_t begin = hash_pointer(referent) & weak_table->mask;
    size_t index = begin;
    size_t hash_displacement = 0;
    
    // 从索引对应的位置开始循环查找,直到对象相等为止
    while (weak_table->weak_entries[index].referent != referent) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_table->weak_entries);
        hash_displacement++;

        // 循环次数 > 最大位移次数
        if (hash_displacement > weak_table->max_hash_displacement) {
            return nil; // 未找到
        }
    }
    
    // 已找到
    return &weak_table->weak_entries[index];
}
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
    if (! entry->out_of_line()) { // 如果动态数组未创建
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            // 如果静态数组还有空间
            if (entry->inline_referrers[i] == nil) {
                // 将weak指针存储到静态数组中
                entry->inline_referrers[i] = new_referrer;
                return;
            }
        }
        
        // 如果静态数组已满,就创建长度为4的动态数组
        weak_referrer_t *new_referrers = (weak_referrer_t *)
            calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
        // 将静态数组中存储的weak指针转移到动态数组中
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            new_referrers[i] = entry->inline_referrers[i];
        }
        
        entry->referrers = new_referrers;
        entry->num_refs = WEAK_INLINE_COUNT;
        entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;
        entry->mask = WEAK_INLINE_COUNT-1;
        entry->max_hash_displacement = 0;
    }

    assert(entry->out_of_line()); // 动态数组已创建才能往下执行

    // 如果动态数组中元素个数大于或等于动态数组长度的3/4
    if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {
        // 将动态数组扩容至2倍并将weak指针存储进去
        return grow_refs_and_insert(entry, new_referrer);
    }
    
    // 索引 = weak指针 & mask
    size_t begin = w_hash_pointer(new_referrer) & (entry->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    
    // 从索引对应的位置开始循环查找,直到有空位置为止
    while (entry->referrers[index] != nil) {
        hash_displacement++;
        index = (index+1) & entry->mask;
        if (index == begin) bad_weak_table(entry);
    }
    if (hash_displacement > entry->max_hash_displacement) {
        entry->max_hash_displacement = hash_displacement;
    }
    
    // 将weak指针存储到动态数组中
    weak_referrer_t &ref = entry->referrers[index];
    ref = new_referrer;
    entry->num_refs++;
}
3,移除
void
weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, 
                        id *referrer_id)
{
    // 对象
    objc_object *referent = (objc_object *)referent_id;
    // weak指针
    objc_object **referrer = (objc_object **)referrer_id;

    weak_entry_t *entry;
    if (!referent) return;

    // 在weak_table的weak_entries中查找对象所在的weak_entry_t
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        // 将weak指针从weak_entry_t的数组中移除
        remove_referrer(entry, referrer);
        bool empty = true;
        // 如果动态数组中还有元素
        if (entry->out_of_line()  &&  entry->num_refs != 0) {
            empty = false;
        }
        else { // 如果静态数组中还有元素
            for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
                if (entry->inline_referrers[i]) {
                    empty = false; 
                    break;
                }
            }
        }

        // 如果静态数组和动态数组中都没有元素
        if (empty) {
            // 从weak_table的weak_entries中移除weak_entry_t
            weak_entry_remove(weak_table, entry);
        }
    }
}
static void remove_referrer(weak_entry_t *entry, objc_object **old_referrer)
{
    // 如果动态数组未创建
    if (! entry->out_of_line()) {
        // 将weak指针从静态数组中移除
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            if (entry->inline_referrers[i] == old_referrer) {
                entry->inline_referrers[i] = nil;
                return;
            }
        }
        objc_weak_error();
        return;
    }

    // 索引 = weak指针 & mask
    size_t begin = w_hash_pointer(old_referrer) & (entry->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    
    // 从索引对应的位置开始循环查找,直到找到weak指针为止
    while (entry->referrers[index] != old_referrer) {
        index = (index+1) & entry->mask;
        if (index == begin) bad_weak_table(entry);
        hash_displacement++;
        if (hash_displacement > entry->max_hash_displacement) {
            objc_weak_error();
            return;
        }
    }
    
    // 将weak指针从动态数组中移除
    entry->referrers[index] = nil;
    entry->num_refs--;
}
4,对象销毁时将weak指针置为nil
void 
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
{
    // 对象
    objc_object *referent = (objc_object *)referent_id;

    // 在weak_table的weak_entries中查找对象所在的weak_entry_t
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) {
        return;
    }

    weak_referrer_t *referrers;
    size_t count;
    
    // 如果动态数组已创建
    if (entry->out_of_line()) {
        // 取出动态数组
        referrers = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else { // 如果动态数组未创建
        // 取出静态数组
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    // 将数组中的weak指针都置为nil
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;
            }
            else if (*referrer) {
                objc_weak_error();
            }
        }
    }
    
    // 从weak_table的weak_entries中移除weak_entry_t
    weak_entry_remove(weak_table, entry);
}
三,autoreleasepool的原理
1,__AtAutoreleasePool结构体
int main(int argc, char * argv[]) {
    @autoreleasepool {
        YJPerson *person = [[[YJPerson alloc] init] autorelease];
    }
    return 0;
}
struct __AtAutoreleasePool {
    __AtAutoreleasePool() { // 构造函数
        atautoreleasepoolobj = objc_autoreleasePoolPush();
    }
    ~__AtAutoreleasePool() { // 析构函数
        objc_autoreleasePoolPop(atautoreleasepoolobj);
    }
    void * atautoreleasepoolobj;
};

int main(int argc, char * argv[]) {
    {
        __AtAutoreleasePool __autoreleasepool; // 调用构造函数(初始化)
        YJPerson *person = ((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("YJPerson"), 
                           sel_registerName("alloc")), sel_registerName("init")), sel_registerName("autorelease"));
    } // 调用析构函数(已超出作用域)
    return 0;
} 
int main(int argc, char * argv[]) {
//    @autoreleasepool {
    atautoreleasepoolobj = objc_autoreleasePoolPush();
        YJPerson *person = [[[YJPerson alloc] init] autorelease];
    objc_autoreleasePoolPop(atautoreleasepoolobj);
//    }
}
void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

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

1>调用autorelease方法的对象都是通过AutoreleasePoolPage对象来管理的

2>每个AutoreleasePoolPage对象占用4096个字节,它内部的成员变量占56个字节,剩下的4040个字节用来存储autorelease对象

3>如果一个AutoreleasePoolPage对象存储不下,系统会创建第二个AutoreleasePoolPage对象,依次类推,它们通过双向链表的形式连接在一起

// 假设AutoreleasePoolPage对象的内存地址为0x1000
class AutoreleasePoolPage
{
    magic_t const magic;
    id *next;
    pthread_t const thread;
    AutoreleasePoolPage * const parent;
    AutoreleasePoolPage *child;
    uint32_t const depth;
    uint32_t hiwat;

    // 存储autorelease对象的起始位置
    id * begin() {
        return (id *) ((uint8_t *)this+sizeof(*this)); // 0x1000 + 56(0x0038)= 0x1038
    }

    // 存储autorelease对象的结束位置
    id * end() {
        return (id *) ((uint8_t *)this+SIZE); // 0x1000 + 4096(0x1000)= 0x2000
    }
}
AutoreleasePoolPage
3,存储和释放
int main(int argc, char * argv[]) {
    @autoreleasepool { // b1 = push()
        YJPerson *person1 = [[[YJPerson alloc] init] autorelease];
        YJPerson *person2 = [[[YJPerson alloc] init] autorelease];
        
        @autoreleasepool { // b2 = push()
            YJPerson *person3 = [[[YJPerson alloc] init] autorelease];
            YJPerson *person4 = [[[YJPerson alloc] init] autorelease];
            
            @autoreleasepool { // b3 = push()
                YJPerson *person5 = [[[YJPerson alloc] init] autorelease];
                YJPerson *person6 = [[[YJPerson alloc] init] autorelease];
            } // pop(b3)
        } // pop(b2) 
    } // pop(b1)
    return 0;
}
push pop(b3) pop(b2) pop(b1)

1>push函数会将POOL_BOUNDARY存储到AutoreleasePoolPage对象中,用来标记当前@autoreleasepool的边界

2>调用autorelease方法的对象会存储到AutoreleasePoolPage对象中

3>pop函数会依次释放autorelease对象,直到遇到POOL_BOUNDARY为止

4,_objc_autoreleasePoolPrint函数
// 系统提供的方法,用来打印AutoreleasePoolPage对象中存储的数据
extern void _objc_autoreleasePoolPrint(void);

int main(int argc, char * argv[]) {
    @autoreleasepool {
        YJPerson *person1 = [[[YJPerson alloc] init] autorelease];
        YJPerson *person2 = [[[YJPerson alloc] init] autorelease];
        
        @autoreleasepool {
            YJPerson *person3 = [[[YJPerson alloc] init] autorelease];
            YJPerson *person4 = [[[YJPerson alloc] init] autorelease];
            
            @autoreleasepool {
                YJPerson *person5 = [[[YJPerson alloc] init] autorelease];
                YJPerson *person6 = [[[YJPerson alloc] init] autorelease];
                
                _objc_autoreleasePoolPrint();
            }
        }
    }
    return 0;
}

// 打印
objc[91277]: ##############
objc[91277]: AUTORELEASE POOLS for thread 0x1192485c0
objc[91277]: 9 releases pending. // 总共9条数据
objc[91277]: [0x7fee0d806000]  ................  PAGE  (hot) (cold)
objc[91277]: [0x7fee0d806038]  ################  POOL 0x7fee0d806038 // b1
objc[91277]: [0x7fee0d806040]    0x6000008b4fc0  YJPerson            // person1
objc[91277]: [0x7fee0d806048]    0x6000008b5060  YJPerson            // person2
objc[91277]: [0x7fee0d806050]  ################  POOL 0x7fee0d806050 // b2
objc[91277]: [0x7fee0d806058]    0x6000008b5020  YJPerson            // person3
objc[91277]: [0x7fee0d806060]    0x6000008b4f80  YJPerson            // person4
objc[91277]: [0x7fee0d806068]  ################  POOL 0x7fee0d806068 // b3
objc[91277]: [0x7fee0d806070]    0x6000008b4ec0  YJPerson            // person5
objc[91277]: [0x7fee0d806078]    0x6000008b4ea0  YJPerson            // person6
objc[91277]: ##############
int main(int argc, char * argv[]) {
    @autoreleasepool {
        for (int i = 0; i < 1000; i++) {
            YJPerson *person = [[[YJPerson alloc] init] autorelease];
        }
        _objc_autoreleasePoolPrint();
    }
    return 0;
}

// 打印
objc[91615]: ##############
objc[91615]: AUTORELEASE POOLS for thread 0x10fbbc5c0
objc[91615]: 1001 releases pending.
// 第一个AutoreleasePoolPage对象,full表示已满
objc[91615]: [0x7f93f3802000]  ................  PAGE (full)  (cold)
objc[91615]: [0x7f93f3802038]  ################  POOL 0x7f93f3802038
objc[91615]: [0x7f93f3802040]    0x600002f0b1c0  YJPerson
...
// 第二个AutoreleasePoolPage对象,hot表示正在使用
objc[91615]: [0x7f93f380d000]  ................  PAGE  (hot) 
objc[91615]: [0x7f93f380d038]    0x600002f0d880  YJPerson
...
objc[91615]: ##############
5,源码分析
static inline void *push() 
{
    id *dest;
    if (DebugPoolAllocation) { // AutoreleasePoolPage对象未创建
        // 创建对象并存储POOL_BOUNDARY
        dest = autoreleaseNewPage(POOL_BOUNDARY);
    } else { // 已创建
        // 存储POOL_BOUNDARY
        dest = autoreleaseFast(POOL_BOUNDARY);
    }
    assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
    return dest;
}

static inline id *autoreleaseFast(id obj)
{
    AutoreleasePoolPage *page = hotPage();
    if (page && !page->full()) { // 如果page未满
        // 将POOL_BOUNDARY存储到page中
        return page->add(obj);
    } else if (page) { // 如果page已满
        // 查找未满的page并存储POOL_BOUNDARY
        return autoreleaseFullPage(obj, page);
    } else {
        return autoreleaseNoPage(obj);
    }
}

id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)
{
    assert(page == hotPage());
    assert(page->full()  ||  DebugPoolAllocation);

    // 查找未满的page
    do {
        if (page->child) page = page->child;
        // 如果没有就创建
        else page = new AutoreleasePoolPage(page);
    } while (page->full());

    setHotPage(page);
    // 将POOL_BOUNDARY存储到page中
    return page->add(obj);
}
static inline id autorelease(id obj)
{
    assert(obj);
    assert(!obj->isTaggedPointer());
    // 存储autorelease对象
    id *dest __unused = autoreleaseFast(obj);
    assert(!dest  ||  dest == EMPTY_POOL_PLACEHOLDER  ||  *dest == obj);
    return obj;
}
// 简化代码
static inline void pop(void *token)
{
    AutoreleasePoolPage *page;
    id *stop;
    
    page = pageForPointer(token);
    stop = (id *)token;

    if (PrintPoolHiwat) printHiwat();
    // 释放autorelease对象
    page->releaseUntil(stop);
}

void releaseUntil(id *stop)
{
    // 释放当前page中的autorelease对象
    while (this->next != stop) {
        AutoreleasePoolPage *page = hotPage();

        // 如果当前page都释放完了还没遇到POOL_BOUNDARY,就继续释放上一个page的
        while (page->empty()) {
            page = page->parent;
            setHotPage(page);
        }

        page->unprotect();
        // 依次取出autorelease对象
        id obj = *--page->next;
        memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
        page->protect();

        // 释放autorelease对象
        if (obj != POOL_BOUNDARY) {
            objc_release(obj);
        }
    }

    setHotPage(this);
}
四,autoreleasepool和runloop的关系
1,autorelease对象何时释放
- (void)viewDidLoad {
    [super viewDidLoad];
    
    YJPerson *person = [[[YJPerson alloc] init] autorelease];
    
    NSLog(@"%s", __func__);
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    NSLog(@"%s", __func__);
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    NSLog(@"%s", __func__);
}

// 打印
-[ViewController viewDidLoad]
-[ViewController viewWillAppear:]
-[YJPerson dealloc] // 没在viewDidLoad后面调用
-[ViewController viewDidAppear:] 
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        NSLog(@"%s", __func__);
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    YJPerson *person = [[[YJPerson alloc] init] autorelease];
}

// 打印
-[YJPerson dealloc] // @autoreleasepool还没结束
2,系统在主线程的runloop中注册了2个observer
- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"%@", [NSRunLoop mainRunLoop]);
}

// 部分打印
observers = (
    "<CFRunLoopObserver 0x600001330320 [0x7fff80617cb0]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4808bf54), 
      context = <CFArray 0x600002c607e0 [0x7fff80617cb0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7f9c54802048>\n)}}",
    "<CFRunLoopObserver 0x6000013303c0 [0x7fff80617cb0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4808bf54), 
      context = <CFArray 0x600002c607e0 [0x7fff80617cb0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7f9c54802048>\n)}}"
)
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),         // 1,进入runloop
    kCFRunLoopBeforeTimers = (1UL << 1),  // 2,即将处理timers
    kCFRunLoopBeforeSources = (1UL << 2), // 4,即将处理sources
    kCFRunLoopBeforeWaiting = (1UL << 5), // 32,即将休眠
    kCFRunLoopAfterWaiting = (1UL << 6),  // 64,刚被唤醒
    kCFRunLoopExit = (1UL << 7),          // 128,退出runloop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

1>activities0x1(十进制为1),所以它是用来监听kCFRunLoopEntry

2>当监听到kCFRunLoopEntry时,会调用objc_autoreleasePoolPush函数

1>activities0xa0(十进制为160 = 32 + 128),所以它是用来监听kCFRunLoopBeforeWaitingkCFRunLoopExit

2>当监听到kCFRunLoopBeforeWaiting时,会先调用objc_autoreleasePoolPop函数,再调用objc_autoreleasePoolPush函数

3>当监听到kCFRunLoopExit时,会调用objc_autoreleasePoolPop函数

runloop

1>在程序运行过程中,主线程的runloop不会退出,它会一直循环的处理事件

2>如果没有事件runloop就会休眠,在休眠之前会调用objc_autoreleasePoolPop函数,该函数会释放所有的autorelease对象

3>所以autorelease对象是在当前循环休眠之前释放的

3,局部对象何时释放
- (void)viewDidLoad {
    [super viewDidLoad];
    
    YJPerson *person = [[YJPerson alloc] init];
    
    NSLog(@"%s", __func__);
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    NSLog(@"%s", __func__);
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    NSLog(@"%s", __func__);
}

// 打印
-[ViewController viewDidLoad]
-[YJPerson dealloc] // 在方法结束时释放,因为ARC生成的是release,而不是autorelease
-[ViewController viewWillAppear:]
-[ViewController viewDidAppear:]
上一篇下一篇

猜你喜欢

热点阅读