iOS ,内存分布、内存管理 、isa 指针,散列表(引用计数表,弱引用表)
内核区 ---- 高地址 栈(高地址到低地址,向下扩展,定义的方法或者函数都是存放在栈上) 堆(创建的对象或者被 copy 的block) 未初始化区域(.bss,未初始化的静态变量或者全局变量) 已初始化区域(.data,已经初始化声明的静态变量和全局变量) 代码段(.text,我们写的代码段都存在在此) 保留区
内存管理方案
1.taggedPointer , 对于一些小对象使用,如NSNumber
2.NONPOINTER_ISA,对于64位下的,isa 指针占64个比特位,但是其中可能只有32位够用了,剩余的就浪费了,苹果为了不让内存浪费更好的管理内存,剩下的32位,苹果用来存储和内存管理相关的内容,用来节约内存
3.散列表,引用计数表和弱引用表。
NONPOINTER_ISA:
在64位架构下,如果他的第一位是0 。则代表他是一个 isa 指针,表示当前对象的类对象的地址,如果是1,则不仅代表一个 isa 指针,类对象的地址,里面还存储内存管理相关的内容,第二位代表是否有关联对象,0代表没有,1代表有(has_assoc),第三位,代表当前对象是否含有C++代码(has_cxx_dtor),3-15表示当前对象的类对象内存地址,16-31,也是,32-35位也是,也就是说,13+16+4 = 33位,这些位表示内存地址,接下来的剩余的位数里面,紧跟着6位为 magic 字段,然后下一步,也就是第42位来,来表示是否含有弱引用指针,(weakly_referenced),接下来以为表示当前指针是否正在进行dealloc操作(deallocating),再接下来一位,表示当前isa指针的引用计数是否达到上限(has_sidetable_rc),如果达到了上限需要一个sidetable,来额外存储相关的引用计数内容,剩下的几位(extra_rc),表示额外的引用计数,当引用计数很小的时候就直接存在isa指针当中.
散列表(sideTables):
sideTable 其实是一个 hash 表,下面挂了很多的 sideTable,sidetable 包括自旋锁(spinlock_t),引用计数表(refcountMap),弱引用表(weak_table_t)。
sidetables 为什么是多张表,而不是一张表?:
弱引用表(weak_table_t):
也是一个hash表,key->hash->weak_entry_t,weak_entry_t,其实是一个结构体数组(weakPtr),比如被weak修饰,就存在这个弱引用表中。
iOS Dealloc流程解析 Dealloc 实现原理
总共干了三件事::
- 执行了object_cxxDestruct 函数
- 执行_object_remove_assocations,去除了关联对象.(这也是为什么category添加属性时,在释放时没有必要remove)
- 就是上面写的那个,清空引用计数表并清除弱引用表,将weak指针置为nil
object_cxxDestruct是由编译器生成,这个方法原本是为了++对象析构,ARC借用了这个方法插入代码实现了自动内存释放的工作.
这个释放.
现象:
- 当类拥有实例变量时,这个方法会出现,且父类的实例变量不会导致子类拥有这个方法.
- 出现这个方法和变量是否被赋值,赋值成什么没有关系.
所以, 我们可以认为这个方法就是用来释放该类中的属性的. weak修饰的属性应该不包含在内。
iOS中的循环引用
循环引用的实质:多个对象相互之间有强引用,不能施放让系统回收。
解决循环引用一般是将 strong 引用改为 weak 引用。