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 可以直接对原数据进行操作而不是该数据的拷贝,节省了时间和空间,尤其是对于结构体以及 ...
随机推荐
- Javascript多线程引擎(九)
Javascript多线程引擎(九)--垃圾回收 垃圾回收这个话题对Programer来说是非常老旧的话题, 从手动的malloc/free 到半自动的 引用计数 再到全自动的 mark-sweep ...
- 分布式文件系统之MogileFS工作原理及实现过程
MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上.MogileFS由3个部分组成: 第1个部分:是server端,包 ...
- SpringMVC实现注解式权限验证
SpringMVC学习系列(9) 之 实现注解式权限验证 对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用servle ...
- hibernate 获取实体的表名、主键名、列名(转载+修改)
package com.escs.utils; import java.util.Iterator; import org.hibernate.cfg.AnnotationConfiguration; ...
- 【Oracle】-【COMMIT对索引的影响】-从trace看COMMIT对索引的影响
之前看过老杨http://yangtingkun.itpub.net/post/468/231000的一篇文章,讲述了INSERT操作对全文索引无操作,但DELETE时为了防止删除的数据仍能通过索引的 ...
- SZU:A12 Jumping up and down
Judge Info Memory Limit: 32768KB Case Time Limit: 10000MS Time Limit: 10000MS Judger: Number Only Ju ...
- linux extract rar files
Extract rar-archives If you need to extract rar files in Linux, you have to download and install unr ...
- 4 MySQL与PHP连接
目录: 1. 连接概述2. 创建php文件进行MySQL连接3. 查看连接效果 1. 连接概述 上文讲述了LAMP开发模型,并且使用AppServ进行安装.这时候就要体现优势了.本节将介绍在直接使用P ...
- const 还是 static readonly
到底是 const 还是 static readonly 真的一样? const 和 static readonly 常在程序中用来声明常量,调用方法也没有什么不同,他们真的一样吗?我们可以做个试 ...
- CPU 硬盘性能
CPU 硬盘性能到底相差多少 本文以一个现代的.实际的个人电脑为对象,分析其中CPU(Intel Core 2 Duo 3.0GHz)以及各类子系统的运行速度——延迟和数据吞吐量.通过粗略的估算PC各 ...