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

  

 void *objc_destructInstance(id obj)
{
if (obj) {
Class isa_gen = _object_getClass(obj);
class_t *isa = newcls(isa_gen); // Read all of the flags at once for performance.
bool cxx = hasCxxStructors(isa);
bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen); // This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj); if (!UseGC) objc_clear_deallocating(obj);
} return obj;
}
void objc_clear_deallocating(id obj)
{
assert(obj);
assert(!UseGC); SideTable *table = SideTable::tableForPointer(obj); /* *** THIS LINE *** */ // clear any weak table items
// clear extra retain count and deallocating bit
// (fixme warn or abort if extra retain count == 0 ?)
OSSpinLockLock(&table->slock);
if (seen_weak_refs) {
arr_clear_deallocating(&table->weak_table, obj); /* *** THIS LINE *** */
}
table->refcnts.erase(DISGUISE(obj)); /* *** THIS LINE *** */
OSSpinLockUnlock(&table->slock);
}

  在上面的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/

  

weak引用变量是否线程安全的更多相关文章

  1. ThreadLocal 定义,以及是否可能引起的内存泄露(threadlocalMap的Key是弱引用,用线程池有可能泄露)

    ThreadLocal 也可以跟踪一个请求,从接收请求,处理请求,到返回请求,只要线程不销毁,就可以在线程的任何地方,调用这个参数,这是百度二面的题目,参考: Threadlocal 传递参数(百度二 ...

  2. java代码声明引用变量经验

    1.static只能修饰类的成员变量,不能修饰方法里的局部变量. 因为static是在类加载时候将成员变量存储进方法区的. 加载类的时候,是不去执行方法里的函数的.所以不会馆方法里的代码,自然就不会读 ...

  3. 编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款

    查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...

  4. Java基础-被final修饰的引用变量的指向

    final修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象,那么该引用变量指向的对象的内容可变吗?看下面这个例子: public class Test { public static void ...

  5. PHP GC垃圾回收机制之引用变量回收周期疑问

    普通的引用变量的销毁大家都知道, 当unset的时候如果refcount = 0 则认为无用, 销毁. 但是手册中提到一点会有递归引用的问题,很是奇葩 代码如下 <?php $a = 1; $a ...

  6. C++引用变量(转)

    引用变量 c++中引用变量的使用: 定义: int rate=80; int  & pt=rate 1.pt 是引用变量,申明引用变量时必须将其初始化.pt 和rate 的值指向相同的内存变量 ...

  7. c#问答篇:对象与引用变量-----初学者的困惑

    转自:http://www.cnblogs.com/huangyu/archive/2004/08/02/29622.html 从宏观的角度来看,对象是类的实例.比如: //定义一个名为Someone ...

  8. C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化

    一.内联函数     常规函数和内联函数的区别在于C++编译器如何将他们组合到程序中.编译过程的最终产品是可执行程序--由一组机器语言指令组成.运行程序时,操作系统将这些指令载入到计算机内存中,因此每 ...

  9. C++引用变量学习

    版权所有,转载请注明来源 (1)reference variable(rv) 主要用处是作为方程的形式参数,使用rv 可以直接对原数据进行操作而不是该数据的拷贝,节省了时间和空间,尤其是对于结构体以及 ...

随机推荐

  1. grasp设计模式笔记回顾

    根据讲师所讲做了一下笔记以便自己能方便学习: ------------------------------------------grasp设计模式: grasp(general responsibi ...

  2. ASP.NET SignalR 2.0入门指南

    ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...

  3. IDE编程环境

    Vim配置及说明——IDE编程环境 目录 Vim配置及说明——IDE编程环境 1.基本及字体 2.插件管理 3.主题风格 4.窗口设置 5.目录树导航 6.标签导航 7.taglist 8.多文档编辑 ...

  4. SZU:B85 Alec's Eggs

    Description Eggs Alec has a lot of eggs. One day, he want to sort them in a ascending sequence by we ...

  5. 生成自己的Webapi帮助文档(二)

    经过今天一上午的修改,已经有个基础的框架了,其它功能只能是在实际使用中发现一个修改一个了. 以下是生成的结果示例: 相比昨天,几个Model都有修改,这里就不一一贴代码了,放个代码包上来,有需要的自己 ...

  6. C#多线程--仓库问题引发的故事

    假设有这么个场景,一个仓库,里面有N件货物,现有六个搬运工(用线程模拟),其中2个向仓库放东西,4个往外搬东西.假设1秒能向里放2件货物,同时可向外搬3件货物(线程休眠),现在需要往里放M件货物,一旦 ...

  7. 传说中的华为Python笔试题——两等长整数序列互换元素,序列和的差值最小(修正)

    有两个序列a,b,大小都为n,序列元素的值任意整形数,无序:要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小. 1. 将两序列合并为一个序列,并排序,得到source ...

  8. IOS开发小功能2:二维码扫描界面的设计(横线上下移动)

    效果图如上,实现的是一个二维码扫描界面. 下面我贴出线条上下移动的代码,至于二维码的代码是用的第三方库. 首先是整体的结构: 注意下面的库文件一个都不能少,否则会报错. TLTiltHighlight ...

  9. c# UDP/TCP协议简单实现(简单聊天工具)

    长时间没有摸这两个协议,写个代码温习下 下面是界面 [服务器界面] [登陆界面] [好友列表界面(我登陆了2个)] [聊天界面] 下面大致讲解下用到的内容 1.用户登陆于服务器通信用到的tcp协议,服 ...

  10. Controller 和 Action (2)

    Controller 和 Action (2) 继上一篇文章之后,本文将介绍 Controller 和 Action 的一些较高级特性,包括 Controller Factory.Action Inv ...