iOS底层原理|iOS底层原理 - 内存管理 之 weak
面试题引发的思考:
Q: ARC都帮我们做了什么?
- ARC是 LLVM编译器 和 Runtime系统 相互协作的一个结果。
weak
指针的实现原理。- 利用 哈希表
weak_table
对weak
指针 与 被指向的对象 进行标记、关联; - 当对象销毁释放内存时,通过 标记 对
weak
指针地址 进行查找,把weak
指针 逐个置为nil
。
__strong
:对对象进行retain
;__weak
:不会对对象进行retain
,当对象销毁时,会自动指向nil
;__unsafe_unretained
:不会对对象进行retain
,当对象销毁时,依然指向之前的内存空间(野指针)。
(1) 案例一
// TODO: -----------------Person类-----------------
@interface Person : NSObject
@end@implementation Person
- (void)dealloc {
NSLog(@"%s", __func__);
}
@end// TODO: -----------------ViewController类-----------------
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"begin");
{
// 强指针person 指向 Person对象
Person *person = [[Person alloc] init];
}
NSLog(@"end");
}// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] end
由以上代码可知:
强指针
person
是大括号内部局部变量,大括号执行结束后person
会被销毁,此时没有指针指向Person
对象,Person
对象会被释放,打印结果可以验证。(2) 案例二
// TODO: -----------------ViewController类-----------------
- (void)viewDidLoad {
[super viewDidLoad];
// 强指针
__strong Person *person1;
NSLog(@"begin");
{
Person *person = [[Person alloc] init];
// 强指针person1 指向 Person的对象
person1 = person;
}
NSLog(@"end - %@", person1);
}// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] end - Demo[1234:567890] -[Person dealloc]
由以上代码可知:
强指针
person1
指向Person
的对象,viewDidLoad
执行结束后以后person1
才会销毁,此时没有指针指向Person
对象,Person
对象会被释放,打印结果可以验证。(3) 案例三
// TODO: -----------------ViewController类-----------------
- (void)viewDidLoad {
[super viewDidLoad];
// 弱指针
__weak Person *person2;
NSLog(@"begin");
{
Person *person = [[Person alloc] init];
person2 = person;
}
NSLog(@"end - %@", person2);
}// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] end - (null)
由以上代码可知:
弱指针
person2
指向Person
的对象,大括号执行结束后person
会被销毁,此时没有指针指向Person
对象,Person
对象会被释放,打印结果可以验证。还可以发现:弱指针指向的对象销毁,弱指针的值会自动清空,所以
person2
打印结果为null
。(4) 案例四
// TODO: -----------------ViewController类-----------------
- (void)viewDidLoad {
[super viewDidLoad];
// 不安全弱指针 - 野指针
__unsafe_unretained Person *person3;
NSLog(@"begin");
{
Person *person = [[Person alloc] init];
person3 = person;
}
NSLog(@"end - %@", person3);
}// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
由以上代码可知:
不安全弱指针
person3
指向Person
的对象,大括号执行结束后person
会被销毁,此时没有指针指向Person
对象,Person
对象会被释放,打印结果可以验证。还可以发现:不安全弱指针指向的对象销毁,不安全弱指针依然指向之前的内存空间,所以
person3
会导致坏地址访问。(5) 总结
2. 源码分析
__strong
:对对象进行retain
;__weak
:不会对对象进行retain
,当对象销毁时,会自动指向nil
;__unsafe_unretained
:不会对对象进行retain
,当对象销毁时,依然指向之前的内存空间(野指针)。
(1)
dealloc
方法
由OC源码查找dealloc
方法:文章图片
dealloc函数分析 由OC源码可知:
【iOS底层原理|iOS底层原理 - 内存管理 之 weak】调用(2) 弱指针置为dealloc
方法,会清除成员变量,移除关联对象,并将指向当前对象的弱指针置为nil
。
nil
的具体操作
由iOS底层原理 - 探寻Runtime本质(一)可知:属性isa
的结构中的信息has_sidetable_rc
作用为:
- 判断引用计数器是否过大无法存储在
isa
中;如果为1,那么引用计数会存储在一个叫SideTable
的类的属性中。
SideTable
结构如下:文章图片
SideTable结构 接下来跳到
clearDeallocating
方法,查看如何将指向当前对象的弱指针置为nil
:文章图片
弱指针处理 由OC源码可知:
- 当一个对象
object
被weak
指针指向时,这个weak
指针会以object
作为key
,被存储到sideTable
类的weak_table
这个散列表上对应的一个weak
指针数组里面。- 当一个对象
object
的dealloc
方法被调用时,Runtime会以object
为key
,从sideTable
的weak_table
散列表中,找出对应的weak
指针列表,然后将里面的weak
指针逐个置为nil
。
推荐阅读
- 做一件事情的基本原理是什么()
- 2020-04-07vue中Axios的封装和API接口的管理
- iOS中的Block
- 【读书笔记】贝叶斯原理
- SG平滑轨迹算法的原理和实现
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片
- “写作宝典”《金字塔原理》之读书笔记
- 2019-08-29|2019-08-29 iOS13适配那点事
- Hacking|Hacking with iOS: SwiftUI Edition - SnowSeeker 项目(一)
- 医生随笔(232)不要轻易得罪底层人