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
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引用变量是否线程安全的更多相关文章
- ThreadLocal 定义,以及是否可能引起的内存泄露(threadlocalMap的Key是弱引用,用线程池有可能泄露)
ThreadLocal 也可以跟踪一个请求,从接收请求,处理请求,到返回请求,只要线程不销毁,就可以在线程的任何地方,调用这个参数,这是百度二面的题目,参考: Threadlocal 传递参数(百度二 ...
- java代码声明引用变量经验
1.static只能修饰类的成员变量,不能修饰方法里的局部变量. 因为static是在类加载时候将成员变量存储进方法区的. 加载类的时候,是不去执行方法里的函数的.所以不会馆方法里的代码,自然就不会读 ...
- 编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款
查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...
- Java基础-被final修饰的引用变量的指向
final修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象,那么该引用变量指向的对象的内容可变吗?看下面这个例子: public class Test { public static void ...
- PHP GC垃圾回收机制之引用变量回收周期疑问
普通的引用变量的销毁大家都知道, 当unset的时候如果refcount = 0 则认为无用, 销毁. 但是手册中提到一点会有递归引用的问题,很是奇葩 代码如下 <?php $a = 1; $a ...
- C++引用变量(转)
引用变量 c++中引用变量的使用: 定义: int rate=80; int & pt=rate 1.pt 是引用变量,申明引用变量时必须将其初始化.pt 和rate 的值指向相同的内存变量 ...
- c#问答篇:对象与引用变量-----初学者的困惑
转自:http://www.cnblogs.com/huangyu/archive/2004/08/02/29622.html 从宏观的角度来看,对象是类的实例.比如: //定义一个名为Someone ...
- C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化
一.内联函数 常规函数和内联函数的区别在于C++编译器如何将他们组合到程序中.编译过程的最终产品是可执行程序--由一组机器语言指令组成.运行程序时,操作系统将这些指令载入到计算机内存中,因此每 ...
- C++引用变量学习
版权所有,转载请注明来源 (1)reference variable(rv) 主要用处是作为方程的形式参数,使用rv 可以直接对原数据进行操作而不是该数据的拷贝,节省了时间和空间,尤其是对于结构体以及 ...
随机推荐
- grasp设计模式笔记回顾
根据讲师所讲做了一下笔记以便自己能方便学习: ------------------------------------------grasp设计模式: grasp(general responsibi ...
- ASP.NET SignalR 2.0入门指南
ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...
- IDE编程环境
Vim配置及说明——IDE编程环境 目录 Vim配置及说明——IDE编程环境 1.基本及字体 2.插件管理 3.主题风格 4.窗口设置 5.目录树导航 6.标签导航 7.taglist 8.多文档编辑 ...
- 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 ...
- 生成自己的Webapi帮助文档(二)
经过今天一上午的修改,已经有个基础的框架了,其它功能只能是在实际使用中发现一个修改一个了. 以下是生成的结果示例: 相比昨天,几个Model都有修改,这里就不一一贴代码了,放个代码包上来,有需要的自己 ...
- C#多线程--仓库问题引发的故事
假设有这么个场景,一个仓库,里面有N件货物,现有六个搬运工(用线程模拟),其中2个向仓库放东西,4个往外搬东西.假设1秒能向里放2件货物,同时可向外搬3件货物(线程休眠),现在需要往里放M件货物,一旦 ...
- 传说中的华为Python笔试题——两等长整数序列互换元素,序列和的差值最小(修正)
有两个序列a,b,大小都为n,序列元素的值任意整形数,无序:要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小. 1. 将两序列合并为一个序列,并排序,得到source ...
- IOS开发小功能2:二维码扫描界面的设计(横线上下移动)
效果图如上,实现的是一个二维码扫描界面. 下面我贴出线条上下移动的代码,至于二维码的代码是用的第三方库. 首先是整体的结构: 注意下面的库文件一个都不能少,否则会报错. TLTiltHighlight ...
- c# UDP/TCP协议简单实现(简单聊天工具)
长时间没有摸这两个协议,写个代码温习下 下面是界面 [服务器界面] [登陆界面] [好友列表界面(我登陆了2个)] [聊天界面] 下面大致讲解下用到的内容 1.用户登陆于服务器通信用到的tcp协议,服 ...
- Controller 和 Action (2)
Controller 和 Action (2) 继上一篇文章之后,本文将介绍 Controller 和 Action 的一些较高级特性,包括 Controller Factory.Action Inv ...