代码编织梦想

正文 接 Weak的实现(一)

2 生成新的weak_entry_t插入到weak_entries

/** 
 * Registers a new (object, weak pointer) pair. Creates a new weak
 * object entry if it does not exist.
 * 
 * @param weak_table The global weak table.弱引用全局表
 * @param referent The object pointed to by the weak reference. 弱引用对象
 * @param referrer The weak pointer address. 弱引用指针地址
 */
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;
    objc_object **referrer = (objc_object **)referrer_id;

    if (!referent  ||  referent->isTaggedPointer()) return referent_id;

    // ensure that the referenced object is viable
    // 判断对象是否正在释放或者是否支持弱引用
    bool deallocating;
    if (!referent->ISA()->hasCustomRR()) {
        deallocating = referent->rootIsDeallocating();
    }
    else {
        BOOL (*allowsWeakReference)(objc_object *, SEL) = 
            (BOOL(*)(objc_object *, SEL))
            object_getMethodImplementation((id)referent, 
                                           @selector(allowsWeakReference));
        if ((IMP)allowsWeakReference == _objc_msgForward) {
            return nil;
        }
        deallocating =
            ! (*allowsWeakReference)(referent, @selector(allowsWeakReference));
    }

    if (deallocating) {
        if (crashIfDeallocating) {
            _objc_fatal("Cannot form weak reference to instance (%p) of "
                        "class %s. It is possible that this object was "
                        "over-released, or is in the process of deallocation.",
                        (void*)referent, object_getClassName((id)referent));
        } else {
            return nil;
        }
    }

    // now remember it and where it is being stored
    // 如果对象已经在weak_table中存在弱引用记录,就原来的entry上面追加
    weak_entry_t *entry;
    //<<1.1>>
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
    //<<2.1>>
        append_referrer(entry, referrer);
    } 
    else {
        //创建新的entry,添加到weak_table中
        //<<2.2>>
        weak_entry_t new_entry(referent, referrer);
        //<<2.3>>
        weak_grow_maybe(weak_table);
        //<<2.4>>
        weak_entry_insert(weak_table, &new_entry);
    }

    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.

    return referent_id;
}

2.1 在weak_entry_t添加新的弱引用weak_referrer_t

/** 
 * Add the given referrer to set of weak pointers in this entry.
 * Does not perform duplicate checking (b/c weak pointers are never
 * added to a set twice). 
 *
 * @param entry The entry holding the set of weak pointers. 某个类的弱引用表
 * @param new_referrer The new weak pointer to be added.新的弱引用
 */
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
    //如果inline_referrers中还能存放weak_referrer_t就放在inline_referrers里面
    if (! entry->out_of_line()) {
        // Try to insert inline.
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            if (entry->inline_referrers[i] == nil) {
                entry->inline_referrers[i] = new_referrer;
                return;
            }
        }

        // Couldn't insert inline. Allocate out of line.
        // 如果放不下了,就创建把所有的weak_referrer_t挪到referrers中
        weak_referrer_t *new_referrers = (weak_referrer_t *)
            calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
        // This constructed table is invalid, but grow_refs_and_insert
        // will fix it and rehash it.
        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.1.1>>
        return grow_refs_and_insert(entry, new_referrer);
    }
    //在referrers中找到一个值为nil的weak_referrer_t对象,用新的弱引用对其赋值,并自增数量
    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_referrer_t &ref = entry->referrers[index];
    ref = new_referrer;
    entry->num_refs++;
}
  • 如果weak_table_t中存在当前对象的弱引用记录weak_entry_t,使用该方法在weak_entry_t添加新的weak_referrer_t
  • 如果weak_entry_t中的weak_referrer_t数量不超过4个,即weak_referrer_t用还保存在inline_referrers中,就将其添加到inline_referrers中;
  • 如果刚好满4个,就将所有的weak_referrer_t从定长数组inline_referrers中取出,开辟新的空间,存储到动态数组referrers中来记录引用
  • 如果weak_referrer_t的数量大于表内存大小的3/4,自动扩容<<2.2.1>>
  • referrers找到第一个为nilweak_referrer_t指针,新的weak_referrer_t赋值给它,引用计数自增。

2.1.1 增加某个对象弱引用表的容量

/** 
 * Grow the entry's hash table of referrers. Rehashes each
 * of the referrers.
 * 
 * @param entry Weak pointer hash set for a particular object.某个对象的弱引用表
 */
__attribute__((noinline, used))
static void grow_refs_and_insert(weak_entry_t *entry, 
                                 objc_object **new_referrer)
{
    ASSERT(entry->out_of_line());
    //原来表大小
    size_t old_size = TABLE_SIZE(entry);
    //新表大小,old_size大于0,新size就变成原来大小的两倍,否则就8个字节大小
    size_t new_size = old_size ? old_size * 2 : 8;

    //原来的弱引用数量
    size_t num_refs = entry->num_refs;
    //原来的弱引用数组
    weak_referrer_t *old_refs = entry->referrers;
    //新的mask
    entry->mask = new_size - 1;
    
    //重新分配entry的内存
    entry->referrers = (weak_referrer_t *)
        calloc(TABLE_SIZE(entry), sizeof(weak_referrer_t));
    entry->num_refs = 0;
    entry->max_hash_displacement = 0;
    
    //先将老的引用全部插入到新的数组里面
    for (size_t i = 0; i < old_size && num_refs > 0; i++) {
        if (old_refs[i] != nil) {
            //递归调用 插入weak_referrer_t
            append_referrer(entry, old_refs[i]);
            num_refs--;
        }
    }
    // Insert
    // 最后插入新加入的弱引用
    append_referrer(entry, new_referrer);
    if (old_refs) free(old_refs);
}

此方法重新定义了对象弱引用表weak_entry_t的大小

  1. 原来的表大小等于0,就分配8个字节
  2. 如果原来表大小大于0,就分配原来大小2倍的字节
  3. 然后为referrers重新分配内存,先将老的weak_entry_t迁移过去,再插入新的weak_entry_t。通过递归调用append_referrer实现插入数据

2.2 创建新的weak_entry_t

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就该对象建一个新的,从源码可看出newReferrer先保存在inline_referrers

2.3 weak_table_t的扩容

// Grow the given zone's table of weak references if it is full.
static void weak_grow_maybe(weak_table_t *weak_table)
{
    size_t old_size = TABLE_SIZE(weak_table);

    // Grow if at least 3/4 full.
    if (weak_table->num_entries >= old_size * 3 / 4) {
        //<<2.3.1>>
        weak_resize(weak_table, old_size ? old_size*2 : 64);
    }
}

-如果weak_tablenum_entries数组的数量大于其内存大小的3/4就开始为weak_table扩容

  • oldsize大于0,扩容为原来大小的两倍
  • 否则分配64字节

2.3.1 weak_resize

static void weak_resize(weak_table_t *weak_table, size_t new_size)
{
    size_t old_size = TABLE_SIZE(weak_table);

    weak_entry_t *old_entries = weak_table->weak_entries;
    weak_entry_t *new_entries = (weak_entry_t *)
        calloc(new_size, sizeof(weak_entry_t));

    weak_table->mask = new_size - 1;
    weak_table->weak_entries = new_entries;
    weak_table->max_hash_displacement = 0;
    weak_table->num_entries = 0;  // restored by weak_entry_insert below
    
    if (old_entries) {
        weak_entry_t *entry;
        weak_entry_t *end = old_entries + old_size;
        for (entry = old_entries; entry < end; entry++) {
            if (entry->referent) {
                //<<2.3.1.1>>
                weak_entry_insert(weak_table, entry);
            }
        }
        free(old_entries);
    }
}

  • 创建新的指针数组new_entries,分配新的大小
  • 遍历将老的数据迁移到新的数组中

2.3.1.1 向weak_table_t中插入weak_entry_t

/** 
 * Add new_entry to the object's table of weak references.
 * Does not check whether the referent is already in the table.
 */
static void weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry)
{
    weak_entry_t *weak_entries = weak_table->weak_entries;
    ASSERT(weak_entries != nil);

    size_t begin = hash_pointer(new_entry->referent) & (weak_table->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (weak_entries[index].referent != nil) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_entries);
        hash_displacement++;
    }

    weak_entries[index] = *new_entry;
    weak_table->num_entries++;

    if (hash_displacement > weak_table->max_hash_displacement) {
        weak_table->max_hash_displacement = hash_displacement;
    }
}

还是通过BITMASK来遍历所有的weak_entry_t,直到有一个referentnil,就将新的weak_entry_t赋值给它。

2.4 将对象的新weak_entry_t插入到weak_table_t

/** 
 * Add new_entry to the object's table of weak references.
 * Does not check whether the referent is already in the table.
 */
static void weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry)
{
    weak_entry_t *weak_entries = weak_table->weak_entries;
    ASSERT(weak_entries != nil);
    //遍历weak_entries,直到weak_entries[index].referent为nil
    size_t begin = hash_pointer(new_entry->referent) & (weak_table->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (weak_entries[index].referent != nil) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_entries);
        hash_displacement++;
    }
    //将新的数据赋值给referent为nil的指针
    weak_entries[index] = *new_entry;
    //weak_entry_t数量+1
    weak_table->num_entries++;
    //更新max_hash_displacement
    if (hash_displacement > weak_table->max_hash_displacement) {
        weak_table->max_hash_displacement = hash_displacement;
    }
}

  • 遍历weak_table_t中的weak_entries,直到有一个weak_entry_t的为referentnil
  • 将新的weak_entry_t赋值给referentnilweak_entry_t
  • 更新num_entriesmax_hash_displacement的数量

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/u014219492/article/details/111068606

开发也可以改变下,RxSwift-让你的开发变得简洁高效。-爱代码爱编程

RxSwift到底是什么? RxSwift是一种函数式响应式编程。那什么是函数式编程呢,函数式编程最重要的概念就是“无状态(immutable)”,看到这有些小伙伴可能会很开心,无状态(知名LOL职业选手)嘛,我是他的粉丝!言归正传,到底什么是“无状态(immutable)”呢?我看了很多文章,但是都被他们专业的描述整的一头雾水,我来说说我的看法:有丰富

iOS 边学边记 Weak的实现(一)-爱代码爱编程

本文较长分三篇按序阅读体验更佳,第四篇为辅助阅读按需看 1.Weak的实现(一) 2.Weak的实现(二) 3.Weak的实现(三) 4.Weak的实现-&SideTables()[oldObj] 带着问题看源码: 1.大家都知道weak的底层实现是一个散列表,那么散列表的结构是什么样的? 2.散列表的key是什么,value是什么,散列函数是怎

iOS核心动画:图层的树状结构-爱代码爱编程

这篇文章主要为大家详细介绍了iOSiOS核心动画:图层的树状结构,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。 Core Animation其实是一个令人误解的命名。你可能认为它只是用来做动画的,但实际上它是从一个叫做Layer Kit这么一个不怎么和动画有关的名字演变而来,所以做动画这只是Core Animation特性的冰山一角。

iOS底层探索--内存管理(上)-爱代码爱编程

兄弟们,最近实在是太忙了。不过~我又回来继续探索了。 内存管理这个名词,我相信所有的iOS工程师都听说过,也是大多数兄弟们,面试最头疼的,今天!小谷带大家走一波源码。希望对大家有所帮助。 关于内存管理,大家都会想到,ARC/MRC、retain、release、dealloc、autorelease。今天就浅谈一波。不对的地方,我在查源码找找,哈哈~

iOS上获取崩溃日志的N+1种方法-爱代码爱编程

iOS上获取崩溃日志的N+1种方法 正常情况下,程序崩溃之后都会有崩溃日志保存在我们的手机里面,当崩溃的时候,我们可以通过如下几种方式找到我们的崩溃日志。  方法一:从本机隐私设置里面的里面导出来       当本机发生崩溃的时候,你可以从系统设置->隐私->分析与改进里面找到你当时的崩溃日志,通常,你的崩溃日志格式包含程序包名,时

如何使用VIPER构建iOS应用-爱代码爱编程

用VIPER构建iOS应用 为避免撕逼,提前声明:本文纯属翻译,仅仅是为了学习,加上水平有限,见谅! 【原文】https://www.objc.io/issues/13-architecture/singletons/ 用VIPER构建iOS应用 ——by Jeff Gilbert and Conrad Stoll 众所周知,在建筑领域,我们塑造我

开发也可以改变下,RxSwift-让你的开发变得简洁高效。-爱代码爱编程

RxSwift到底是什么? RxSwift是一种函数式响应式编程。那什么是函数式编程呢,函数式编程最重要的概念就是“无状态(immutable)”,看到这有些小伙伴可能会很开心,无状态(知名LOL职业选手)嘛,我是他的粉丝!言归正传,到底什么是“无状态(immutable)”呢?我看了很多文章,但是都被他们专业的描述整的一头雾水,我来说说我的看法:有丰富

iOS 边学边记 Weak的实现(一)-爱代码爱编程

本文较长分三篇按序阅读体验更佳,第四篇为辅助阅读按需看 1.Weak的实现(一) 2.Weak的实现(二) 3.Weak的实现(三) 4.Weak的实现-&SideTables()[oldObj] 带着问题看源码: 1.大家都知道weak的底层实现是一个散列表,那么散列表的结构是什么样的? 2.散列表的key是什么,value是什么,散列函数是怎

常见多线程实现,iOS开发程序猿进阶-爱代码爱编程

一 常见多线程实现 (一)pthread (1)特点 1)一套通用的多线程API2)适用于Unix/Linux/Windows等系统3)跨平台可移植4)使用难度大(2)使用语言 C语言 (3)使用频率 几乎不用 (4)线程生命周期 由程序员进行管理 (5)概念、属性与方法 略 (二)NSThread (1)特点 1)使用更加面向对

iOS多线程的锁,你知道多少?-爱代码爱编程

前言 iOS开发中由于各种第三方库的高度封装,对锁的使用很少,刚好之前面试中被问到的关于并发编程锁的问题,都是一知半解,于是决定整理一下关于iOS中锁的知识,为大家查缺补漏。 目录 第一部分: 什么是锁 第二部分: 锁的分类 第三部分: 性能对比 第四部分: 常见的死锁 第五部分: 总结(附Demo) 正文 一、什么是锁 在过去几十年并

iOS 边学边记 Weak的实现(三)-爱代码爱编程

正文 接 Weak的实现(二) 3 设置弱引用标志位 inline void objc_object::setWeaklyReferenced_nolock() { retry: //去对象的isa指针 isa_t oldisa = LoadExclusive(&isa.bits); isa_t newisa = ol

关于iOS系统你知道多少???-爱代码爱编程

首先来说下ios的历史吧!!! iOS系统诞生于2007年1月1日的Macworld上,当天公布了IOS的初代系统,当时它的名字是iPhone OS X,同时颠覆手机行业的iPhone也横空出世了,它创新的多点触控操作以及极简的用户体验都让全球消费者为之疯狂,3.5英寸的480X320分辨率的大屏幕也远远超过当时手机行业的平均配置,单Home键让 当时标配