zoukankan      html  css  js  c++  java
  • weak引用变量是否线程安全

    1、在ARC出现之前,Objetive-C的内存管理需要手工执行release&retain操作,这些极大增加了代码的编写难度,同时带来很多的crash。

       同时大量的delegate是unretain的,如果忘记在dealloc中主动设置为空,将带来野指针的隐患。由于dealloc是一个线程不安全的方法

       在MRC的环境下面,如果一个对象在一个线程中正在释放过程当中,这个对象在另外一个线程收到通知,极有可能带来Crash,

      这个取决于执行的方法中访问的对象内存是否被破坏掉。

    2、ARC出现之后带来了weak修饰符,降低了野指针出现的概率,同时将dealloc方法进行了修改,用户不需要主动调用[super dealloc],由编译器插入。

       同时编译器插入了一个cxx_dealloc的方法,这个方法真正释放该对象持有的变量,dealloc方法只能算作即将释放的一个回调,那么ARC下面dealloc是怎么执行的呢。

    3、dealloc的方法执行

      1、一个对象执行release方法,引用计数减少1,变成0

      2、调用该对象的dealloc方法

      3、该对象dealloc方法执行完毕调用父类的dealloc方法

      4、调用NSObject的dealloc方法

      5、NSObject的dealloc方法执行_objc_rootDealloc(self);

      6、_objc_rootDealloc 中调用 object_dispose()

      7、object_dispose 中调用 objc_destructInstance()

      8、objc_destructInstance 调用 objc_clear_deallocating

      

     1 void *objc_destructInstance(id obj)
     2 {
     3     if (obj) {
     4         Class isa_gen = _object_getClass(obj);
     5         class_t *isa = newcls(isa_gen);
     6 
     7         // Read all of the flags at once for performance.
     8         bool cxx = hasCxxStructors(isa);
     9         bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
    10 
    11         // This order is important.
    12         if (cxx) object_cxxDestruct(obj);
    13         if (assoc) _object_remove_assocations(obj);
    14 
    15         if (!UseGC) objc_clear_deallocating(obj);
    16     }
    17 
    18     return obj;
    19 }
    20 void objc_clear_deallocating(id obj) 
    21 {
    22     assert(obj);
    23     assert(!UseGC);
    24 
    25     SideTable *table = SideTable::tableForPointer(obj); /* *** THIS LINE *** */
    26 
    27     // clear any weak table items
    28     // clear extra retain count and deallocating bit
    29     // (fixme warn or abort if extra retain count == 0 ?)
    30     OSSpinLockLock(&table->slock);
    31     if (seen_weak_refs) {
    32     arr_clear_deallocating(&table->weak_table, obj); /* *** THIS LINE *** */
    33     }
    34     table->refcnts.erase(DISGUISE(obj)); /* *** THIS LINE *** */
    35     OSSpinLockUnlock(&table->slock);
    36 }

      在上面的objc_destructInstance代码中,首先释放object_cxxDestruct方法,这里面会逐级往上移出对象的实例变量

      然后移除关联对象

      第三步中清空了weak指针

      可以看出来,清除一个对象的实例变量是统一清理的,由下逐级往上。

      在清理weak指针的时候如何保证这个对象在dealloc收到消息的时候还是线程安全的呢?

      答案下面:

        得到一个weak 指针的时候会执行下面的方法,该方法中有一个spinlock,这个锁在清理weak指针的时候同时会用到,所以是线程安全的。

        也就是这个weak指针获得的结果要么为空,要么不为空,只要不为空,就代表这个指针指向的内存区域没有被释放掉,其对象内部的实例变量还是有可能被清理掉的。

        这个时候向这个指针发送消息,不会带来crash,但是逻辑可能异常,这种情况理论上存在。

    id objc_loadWeakRetained(id *location)
    {
        id result;
    
        SideTable *table;
        spinlock_t *lock;
    
     retry:
        result = *location;
        if (!result) return nil;
    
        table = SideTable::tableForPointer(result);
        lock = &table->slock;
    
        spinlock_lock(lock);
        if (*location != result) {
            spinlock_unlock(lock);
            goto retry;
        }
    
        result = weak_read_no_lock(&table->weak_table, location);
    
        spinlock_unlock(lock);
        return result;
    }
    

      

    4、参考资料

      http://stackoverflow.com/questions/30673101/is-it-safe-to-read-a-weak-pointer-while-its-being-deallocated

      http://stackoverflow.com/questions/14854635/how-can-the-objective-c-runtime-know-whether-a-weakly-referenced-object-is-still/14854977#14854977

      http://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/

      

  • 相关阅读:
    Running OOM killer script for process 32248 for Solr on port 8983
    List删除元素
    Oracle联合主键
    synchronized的四种用法
    数据库 乐观锁与悲观锁
    noip2011普及组 统计单词数
    bzoj3751 noip2014解方程
    汕头市队赛SRM07
    noip2010 导弹拦截&&vijos1810
    noip2009普及组 细胞分裂&&vijos1814
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/6275077.html
Copyright © 2011-2022 走看看