一、引用计数的存储
在64bit中,引用计数可以直接存储在优化过的isa指针extra_rc,如果引用计数器过大无法存储在isa中,会将isa中的has_sidetable_rc赋值为1,将引用计数存储在SideTable类中,以一个散列表形式保存
inline uintptr_t
objc_object::rootRetainCount()
{
if (isTaggedPointer()) return (uintptr_t)this;
sidetable_lock();
isa_t bits = LoadExclusive(&isa.bits);
ClearExclusive(&isa.bits);
/*
nonpointer
0,代表普通的指针,存储着Class、Meta-Class对象的内存地址
1,代表优化过,使用位域存储更多的信息
*/
if (bits.nonpointer) {
// 从extra_rc中取出引用计数
uintptr_t rc = 1 + bits.extra_rc;
// 如果has_sidetable_rc为1,再从sidetable中取出引用计数
if (bits.has_sidetable_rc) {
rc += sidetable_getExtraRC_nolock();
}
sidetable_unlock();
return rc;
}
sidetable_unlock();
return sidetable_retainCount();
}
二、weak指针的实现原理
弱引用存在哈希表中,销毁时取出当前对象的弱引用表,把弱引用都清除掉。
弱引用表和isa存储不下的引用计数,都存放在SideTable类中


三、自动释放池的本质
autoreleasepool本质:
1、autoreleasepool其实也是一个结构体__AtAutoreleasePool,里边有一个构造函数和一个析构函数,
在大括号开始的位置调用他的构造函数,atautoreleasepoolobj = objc_autoreleasePoolPush();
大括号结束的时候调用他的析构函数,objc_autoreleasePoolPop(atautoreleasepoolobj);
在大括号中,调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的。
2、 AutoreleasePoolPage的结构

- 每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址
- 所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起,成员变量parent指向的上一个对象,成员变量child指向下一个对象
- 调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址
- 调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
-
成员变量id *next是指向了下一个能存放autorelease对象地址的区域
image
3、嵌套使用
嵌套使用
嵌套使用结构(一页就够存储,不需要三页,为了方便)
image.png
四、Runloop和Autorelease
Autorelease对象是在当前的runloop迭代结束时释放
当监听到进入runloop的时候,调用push函数
当休眠的时候,会将当前自动释放池pop,并且重新push
当退出runloop的时候,会调用pop函数
网友评论