精华内容
下载资源
问答
  • weak实现原理

    2017-12-13 03:10:29
    ###weak实现原理 1.为了管理所有对象的引用计数和weak指针,创建了一个全局的SideTables。这是一个Hash表,里面装的是SideTable,用对象地址内存地址作为key进行散列。苹果内部将整个SideTables分为64分,所以就有64...

    前段时间看了iOS管理对象内存的数据结构以及操作算法后感觉受益良多,所以对照源码进行了一遍自己的梳理。 ###weak实现原理 1.为了管理所有对象的引用计数和weak指针,创建了一个全局的SideTables。这是一个Hash表,里面装的是SideTable,用对象地址内存地址作为key进行散列。苹果内部将整个SideTables分为64分,所以就有64个SideTable。 SideTable结构如下:

    struct SideTable {
    //加锁,保证线程安全
    spinlock_t slock;
    /*一张记录引用计数器的散列表。
    */
    RefcountMap refcnts;
    weak_table_t weak_table;
    
    SideTable() {
    memset(&weak_table, 0, sizeof(weak_table));
    }
    
    ~SideTable() {
    _objc_fatal("Do not delete SideTable.");
    }
    
    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
    
    // Address-ordered lock discipline for a pair of side tables.
    
    template<bool HaveOld, bool HaveNew>
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template<bool HaveOld, bool HaveNew>
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
    };
    
    复制代码

    通过table.refcnts.find(this)找到对象的真正引用计数器ref,ref是size_t类型的,然后通过bit mask进行内容存储

    // The order of these bits is important.
    #define SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0) //是否有弱指针指向这个对象,1代表有
    #define SIDE_TABLE_DEALLOCATING      (1UL<<1)  // 是否正在被销毁,1代表是
    #define SIDE_TABLE_RC_ONE            (1UL<<2)  //真正的引用计数
    #define SIDE_TABLE_RC_PINNED         (1UL<<(WORD_BITS-1)) //最大的引用计数次数
    
    复制代码

    然后我们看看SideTabel中的weak_table_t weak_table,它是如下结构

    struct weak_table_t {
    weak_entry_t *weak_entries; //一个放置weak_entry_t的数组
    size_t    num_entries;
    uintptr_t mask;
    uintptr_t max_hash_displacement;
    };
    
    //weak_entry_t的数据结构
    struct weak_entry_t {
    DisguisedPtr<objc_object> referent;
    union {
    struct {
    weak_referrer_t *referrers;
    uintptr_t        out_of_line_ness : 2;
    uintptr_t        num_refs : PTR_MINUS_2;
    uintptr_t        mask;
    uintptr_t        max_hash_displacement;
    };
    struct {
    // out_of_line_ness field is low bits of inline_referrers[1]
    weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
    };
    };
    
    bool out_of_line() {
    return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
    }
    
    weak_entry_t& operator=(const weak_entry_t& other) {
    memcpy(this, &other, sizeof(other));
    return *this;
    }
    
    weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
    : referent(newReferent)
    {
    inline_referrers[0] = newReferrer;
    for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
    inline_referrers[i] = nil;
    }
    }
    };
    
    复制代码

    在weak_entry_t中,我们看到一个类型为DisguisedPtr,名为referent的指针,这里的被指向对象的地址,存储的是我看到对这个变量苹果的注释如下

    //DisguisedPtr<T> acts like pointer type T*, except the
    // stored value is disguised to hide it from tools like `leaks`.
    复制代码

    说是对指针的一种封装,目的是防止泄露。 接下来是weak_referrer_t, ,存储的是弱引用对象的地址。

    // The address of a __weak variable.
    // These pointers are stored disguised so memory analysis tools
    // don't see lots of interior pointers from the weak table into objects.
    typedef DisguisedPtr<objc_object *> weak_referrer_t;
    复制代码

    至于weak_referrer_t inline_referrers 当弱引用对象不多于4个时候,实际弱引用对象的地址存在这里面的,多余4个则存referrers里。

    介绍完基本构成之后我们再来看看retain,release,retainCount这些操作是怎么实现的。(这里不讨论alloc 是因为alloc只涉及到内存的分配和isa的初始化,与上文讲的无关) retain:

    //下面是对对象进行retain,可以看到是如何实现引用计数加1的
    id objc_object::sidetable_retain()
    {
    //isa指针不能是taggedPointer(若是,就会在isa中进行引用计数的存储)
    #if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
    #endif
    SideTable& table = SideTables()[this];
    
    table.lock();
    //从散列表中获取这个size_t
    size_t& refcntStorage = table.refcnts[this];
    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
    //当小于最大引用计数,引用计数+1 (这里是二进制加法)
    refcntStorage += SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    
    return (id)this;
    }
    复制代码

    reaintCount:

    uintptr_t objc_object::sidetable_retainCount()
    {
    SideTable& table = SideTables()[this];
    
    //引用计数初始化为1
    size_t refcnt_result = 1;
    
    table.lock();
    //迭代获取RefcountMap,key为objc_object也就是内存地址,value为引用计数
    RefcountMap::iterator it = table.refcnts.find(this);
    //当找到RefcountMap
    if (it != table.refcnts.end()) {
    // c++语法,在迭代器中,first代表key,second代表value 。所以it->second 取的value也就是引用计数,然后右移两位再+1,这是因为低两位记录了其他状态,见上文
    refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
    }
    table.unlock();
    //所以获取的引用计数>=1
    return refcnt_result;
    }
    复制代码

    release:

    uintptr_t objc_object::sidetable_release(bool performDealloc)
    {
    #if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
    #endif
    SideTable& table = SideTables()[this];
    
    bool do_dealloc = false;
    
    table.lock();
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) {
    //假如迭代器没有找到RefcountMap,结果标记为false,size_t标记为释放中
    do_dealloc = true;
    table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
    } else if (it->second < SIDE_TABLE_DEALLOCATING) {
    // 当引用计数为0且size_t没有被标记为释放中时,进行标记
    do_dealloc = true;
    it->second |= SIDE_TABLE_DEALLOCATING;
    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
    //没有超过最大引用计数时,且引用计数不为0时引用计数减1(二进制减法)
    it->second -= SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    if (do_dealloc  &&  performDealloc) {
    ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
    }
    return do_dealloc;
    }
    复制代码

    最后放入我画的一张图

    展开全文
  • iOS weak 实现原理

    2018-09-23 00:08:23
    如何实现 weak 现在我们将 weak 的思路整理一下: 整个系统中存在很多个对象,这些对象都可能会被弱引用,那么我们需要一个容器来容纳这些被弱引用的对象,比如数组,在此将这个容器的数据结构标识为 ...

    weak 关键字的作用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil.

    如何实现 weak

    1. 现在我们将 weak 的思路整理一下:

    2. 整个系统中存在很多个对象,这些对象都可能会被弱引用,那么我们需要一个容器来容纳这些被弱引用的对象,比如数组,在此将这个容器的数据结构标识为 objectContainerDataStructure

    3. 一个对象可能会被多次弱引用,当这个对象被销毁时,我们需要找到这个对象的所有弱引用,所以我们需要将这些弱引用的地址(即指针)放在一个容器里,比如数组,在此将这些弱引用的地址的数据结构标识为pointerContainerDataStructure

    4. 当对象不再被强引用时需要销毁的时候,我们需要通过这个对象在 objectContainerDataStructure 找到其对应的pointerContainerDataStructure,进而找到这个对象的所有弱引用,将其置为nil

    5. 通过上面的步骤,我们大概可以得出这么一个数据结构:

    6. pointerContainerDataStructure 仅仅只是容纳一个对象的所有弱引用的地址,所以用数组即可;

    7. objectContainerDataStructure 是一个 key-value 数据结构,将对象作为 key,对象的内存地址是最好的选择;

    8. iOS 中常用的 key-value 数据结构就是字典 Dictionary ,在这里我们的key 是一个数值对象,value 则是一个数值数组对象,可以用哈希表实现;

    9. 总结

    为了实现 weak,我们需要这样的一张弱引用表:

    1. 表的数据结构是哈希表;

    2. 表的 key 是对象的内存地址;

    3. value 是指向该对象的所有弱引用的指针;

    结尾

     

    上面是如何自己实现weak 的一个大概思路,Apple 的实现可以看iOS底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)一文。

     

    【从历年weak看iOS面试】
     2013年
    面试官:代理用weak还是strong?
    我 :weak 。 
    面试官:明天来上班吧

     2014年
    面试官:代理为什么用weak不用strong?
    我 : 用strong会造成循环引用。
    面试官:明天来上班吧

     2015年
    面试官:weak是怎么实现的?
    我 :weak其实是 系统通过一个hash表来实现对象的弱引用
    面试官:明天来上班吧

     2016年
    面试官:weak是怎么实现的?
    我 :runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
    面试官:明天来上班吧

     2017年
    面试官:weak是怎么实现的?
    我 : 1 初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
             2    添加引用时:objc_initWeak函数会调用 storeWeak() 函数, storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
              3    释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
    面试官:明天来上班吧

     2018年
    面试官:weak是怎么实现的?
    我 :跟2017年说的一样,还详细补充了objc_initWeak, storeWeak, clearDeallocating的实现细节。
    面试官:小伙子基础不错。13k ,996干不干?干就明天来上班。。   下一个

    2019年
    面试官:weak是怎么实现的?
    我 :     别说了,拿纸来,我动手实现一个。
    面试官:等写完后,面试官慢悠悠的说,小伙子不错,我考虑考虑,你先回去吧

     

    展开全文
  • 内存管理原理 两张表 1.引用计数表 (引用计数值, 是否为弱引用) 2.引用地址表 当对象将要被销毁时, 判断是否为弱引用, 有弱引用遍历弱引用地址列表设置为nil执行销毁操作   Runtime维护了一个weak表,用于...

    内存管理原理

    两张表

    1.引用计数表 (引用计数值, 是否为弱引用)

    2.引用地址表

    当对象将要被销毁时, 判断是否为弱引用, 有弱引用遍历弱引用地址列表设置为nil执行销毁操作

     

    Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。

     

    • 表的 key 是对象的内存地址;

    • value 是指向该对象的所有弱引用的指针;

    展开全文
  • 1.伪代码模拟weak用到的主要表 struct weak_referrer_t{ int weakPtr;//瞎写的不做参考 }; //hash表 struct weak_entry_t{ int index; //存储弱引用该对象的指针的指针的数组 weak_referrer_t inline_...

    1.伪代码模拟weak用到的主要表

    struct weak_referrer_t{
         int weakPtr;//瞎写的不做参考
    };
    
    //hash表
    struct weak_entry_t{
        int index;
        //存储弱引用该对象的指针的指针的数组
        weak_referrer_t inline_referrers[3];
        id referent;//传入的对象
        int count;
    };
    
    //weak_table——hash表
    struct weak_table_t{
        //hash数组,用来存储弱引用对象的相关信息weak_entry_t
        weak_entry_t weak_entries[3];
    };
    struct SideTable {
        //weak_table——hash表
        weak_table_t weak_table;
        
    };
    
    //全局的hash表
    struct SideTables {
        //全局的hash数组
        SideTable SideTable[3];
        
    };
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            struct weak_entry_t weak_entry_t1 = {1,[NSObject alloc]};
            struct weak_entry_t weak_entry_t2 = {2,[NSObject alloc]};
            struct weak_entry_t weak_entry_t3 = {3,[NSObject alloc]};
            
            struct weak_table_t weak_table_t;
            weak_table_t.weak_entries[0] = weak_entry_t1;
            weak_table_t.weak_entries[1] = weak_entry_t2;
            weak_table_t.weak_entries[2] = weak_entry_t3;
            
            struct SideTable SideTable;
            SideTable.weak_table = weak_table_t;
          
           };

    参照链接:https://blog.csdn.net/u013378438/article/details/82790332

    展开全文
  • iOS底层weak实现原理

    2019-01-24 10:29:14
    weak是弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil。那么weak的原理是什么呢?...weak 实现原理的概括 Runtime维护了一个weak表,用于存储指向某个对象的所有we...
  •  weak表是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址数组。weak是弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil。... weak 实现原理的概括  ...
  • 在iOS中,使用weak关键字能够对内存对象进行弱引用,基于这个特性,使用weak...首先在分析weak关键字实现原理之前,先介绍一下相关的数据结构,这些数据结构其中一部分可能在其他地方有所提及,但本文只列出与we...
  • weak实现原理

    千次阅读 2018-05-21 14:15:42
    实现 weakweak 的作用weak 关键字的作用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为 nil。如何实现 weak现在我们将 weak 的思路整理一下:整个系统中存在很多个对象,这些对象都可能...
  • weak 实现原理的概括 Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值...weak实现原理可以概括
  • iOS 中 weak实现原理

    2017-12-13 08:45:14
    本文是看了 iOS 底层解析weak实现原理(包含weak对象的初始化,引用,释放的分析) 一文后,为了加深自己的理解,从自己的角度来讲如何实现类似的功能。 实现 weak weak 的作用 weak 关键字的作用***弱引用***,所...
  • iOS weak底层实现原理

    2018-12-23 15:01:00
    今年年底做了很多决定,离开工作三年的深圳,来到了上海,发现深圳和上海在苹果这方面还是差距有点大的,上海的市场8...咱们闲话少说,今天我们将继续讲述OC修饰属性的一个Weak修饰符的底层实现,有时间我会花时间讲...
  • weak 是弱引用,用 weak 来修饰、描述所引用对象的计数器并不会增加,而且 weak 会在引用对象被释放的时候自动置为 nil,这也就避免了野指针访问坏内存而引起奔溃的情况,另外 weak 也可以解决循环引用。 拓展:为...
  • iOS weak 指针实现原理2

    2019-02-25 09:53:59
    SideTable 结构如下 struct SideTable { spinlock_t slock; ///线程同步锁 RefcountMap refcnts;... /// weak 散列表 所有 weak 指针存放在这个表里 }; weak_table_t 结构如下 struct weak_table_t { ...
  • weak 的内部实现原理

    2017-03-23 10:18:00
    问题 ...在 Friday QA 上,有一期专门介绍 weak实现原理。https://mikeash.com/pyblog/friday-qa-2010-07-16-zeroing-weak-references-in-objective-c.html 《Objective-C高级编程》一书中也介...
  • 是OC中weak功能实现的核心数据结构。 3.1、weak_table_t 先来看下weak_table_t的底层代码。 struct weak_table_t { weak_entry_t *weak_entries; size_t num_entries; uintptr_t mask; uintptr_t max_hash_...
  • 浅谈iOS之weak底层实现原理

    千次阅读 2018-08-12 15:31:25
    前言 在iOS开发过程中,会经常使用到一个修饰词“weak”,使用场景大家都比较清晰,用于一些对象相互引用的时候,...weak底层原理 1.weak编译解析 首先需要看一下weak编译之后具体出现什么样的变化,通过Clang...
  • iOS weak 指针实现原理1

    2019-02-25 09:53:26
    ####__weak 的作用是什么? 先给出一段代码 分别用 __strong __weak __unsafe_unretained 指向这个Persion 对象时控制台输出内容分别是什么? __strong 指向该 Person 对象时 最后Person 才被 dealloc 说明 __strong...
  • 浅谈iOS之weak底层实现原理
  • weak是弱引用,用weak来修饰、描述所引用对象的计数器并不会加1,而且weak会在引用对象被释放的时候自动置为nil,这也就避免了野指针访问坏内存而引起奔溃的情况,另外weak也可以解决循环引用。 拓展:为什么修饰...
  • 问:当weak指向的对象被释放时,如何让weak指针置为nil的呢? 1、调用objc_release 2、因为对象的引用计数为0,所以执行dealloc 3、在dealloc中,调用了_objc_rootDealloc函数 4、在_objc_rootDealloc中,调用了...
  • Runtime维护了一个weak表,用于存储指向某个对象的所有...weak实现原理可以概括一下三步: 1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。 2、添加引用时:objc_init...
  • iOS中weak实现原理

    2018-09-29 16:21:00
    weak表其实是一个hash(哈希)表,key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。 步骤: 初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向...
  • iOS arc weak指针原理

    2020-11-03 11:47:05
    iOS arc weak指针原理 ARC 都帮我们做了什么?... 3.2 weak实现的流程 3.2.1 初始化时:runtime会调用objc_initWeak函数,objc_initWeak函数会初始化一个新的weak指针指向对象的地址。 3.2.2

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 202
精华内容 80
关键字:

weak实现原理