内存5大区 引用计数 iOS中内存管理方案

内存5⼤区

  1. 堆:存放通过 alloc , new , malloc 等创建出来的变量。 ⼀般以0x6开头
  2. 栈区:存放局部变量,⽅法参数, 对象的指针 等。 栈的内存⼤⼩有限,主线程1MB,其他线程 512KB ,栈是线程独有的,栈在线程开始的时候初始化,每个线程的栈互相独⽴ ⼀般以0x7开头 
  3. 全局区/静态区:存放全局变量和静态变量。 ⼀般以0x1开头 ,编译时分配的内存区域在程序运⾏时⼀直存在,直到程序运⾏结束才会被释放
  4. 常量区:常量。(const修饰) ⼀般以0x1开头 ,常量区的内存和全局区⼀样也是在编译阶段进⾏分配,程序运⾏时会⼀直存储在内存中,只有当程序结束后才会由操作系统释放
  5. 代码区:存放编译⽣成的⼆进制代码

引⽤计数

引⽤计数(Reference Count)是⼀个简单⽽有效的管理对象⽣命周期的⽅式。

iOS中的内存管理⽅案

NONPOINTER_ISA , Tagged Pointer , SideTable

Tagged Pointer

Tagged Ponter 是苹果在64位操作系统下提出来的概念,也就是从5S开始。 Tagged Ponter 针

对的是⼩对象类型,⽐如NSNumber、NSDate、NSString。

Tagged Pointer 也是指针,是⼀种被打上了tagged标记的指针。

Tagged Pointer 指针,它表示的不再是地址,⽽是真正的值。这样能够⼤幅度的提升它的访问速

度和创建销毁的速度。因为在栈上,不必在堆上为其分配内存,节省了很多内存开销。在性能上,

根据苹果官⽅的说法, Tagged Pointer 有3倍的空间效率的提升,以及106倍的创建和销毁速度的

提升。

retain流程

  1. 判断是否是 Tagged Pointer , Tagged Pointer 不需要维护引⽤计数,直接返回如果不是 Tagged Pointer ,获取对象的 isa ,然后判断是否是 NONPOINTER_ISA
  2. 如果不是 NONPOINTER_ISA ,交给散列表处理,对其引⽤计数进⾏ ++ 操作,然后返回
  3. 判断是否正在析构,如果是直接返回
  4. 如果是 NONPOINTER_ISA ,对 isa 的 extra_rc 进⾏ ++ 操作
  5. 如果超出了 extra_rc 的最⼤存储范围,就将⼀半的引⽤计数保存在 extra_rc ,并且把 isa的 has_sidetable_rc 置为1,然后将另⼀半的引⽤计数保存到散列表

当引⽤计数超出isa的extra_rc的最⼤存储范围时,为什么要extra_rc和散列表

中各存⼀半呢,为什么不是把所有的引⽤计数的值都存到散列表⾥⾯?

通过isa可以很容易的拿到extra_rc,通过extra_rc进⾏引⽤计数的存储是很⽅便的。散列表是先拿

到SideTable这张表,再在表中拿到引⽤计数表,才能进⾏操作,表操作还要做加锁和解锁操作,

⾮常浪费性能。所以在SideTable存⼀半,这样的话++,--都能够在extra_rc⾥⾯对引⽤计数进⾏操

作,效率能够更⾼。

release流程

  1. 判断是否是 Tagged Pointer , Tagged Pointer 不需要维护引⽤计数,直接返回
  2. 如果不是 Tagged Pointer ,获取对象的 isa ,然后判断是否是 NONPOINTER_ISA
  3. 如果不是 NONPOINTER_ISA ,交给散列表处理,对其引⽤计数进⾏ -- 操作,如果散列表的引⽤计数清零,对该对象执⾏ dealloc 操作,然后返回
  4. 如果是 NONPOINTER_ISA ,对 isa 的 extra_rc 进⾏ -- 操作,当 extra_rc 计数为0,则需要向散列表的引⽤计数借位
  5. 判断 isa 的 has_sidetable_rc 是否为1,如果不为1,对该对象执⾏ dealloc 操作。
  6. 如果 isa 的 has_sidetable_rc 为1,获取散列表的引⽤计数,如果散列表的引⽤计数为0,对该对象执⾏ dealloc 操作
  7. 如果散列表的引⽤计数⼤于0,将引⽤计数-1,然后存⼊ isa 的 extra_rc

dealloc流程

  1. 判断是否是 Tagged Pointer , Tagged Pointer 不需要维护引⽤计数,直接返回
  2. 如果是 NONPOINTER_ISA ,且没有弱引⽤,没有关联对象,没有c++析构函数,没有散列表引⽤计数,直接释放,否则进⾏下⼀步
  3. 调⽤ objc_dispose() 函数
  4. 调⽤ objc_destructInstance() 函数,然后再调⽤ free() 函数释放
  5. objc_destructInstance 函数⾸先判断是否存在c++析构函数和是否存在关联对象,如果有则调⽤c++析构函数、删除关联对象,然后清除弱引⽤表的相关信息和清除散列表的相关信息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值