内存管理相关【内存布局&内存管理方案】

iOS系统下的内存布局

最上面是内核区,最下面是保留区,中间是给程序加载的空间。

从高地址到低地址依次为内核区、栈、堆、静态全局区(未初始化区域.bss和已初始化区域.data)、代码区、保留区;

程序被加载到内存分成三段未初始化数据(.bss)、已初始化数据(.data)和代码段(.text)。

代码段顾名思义存放代码;

已初始化区域:已经初始化声明的静态变量和全局变量;

未初始化区域:未初始化的静态变量和全局变量;

堆heap:创建的对象或被copy的block;

栈stack:定义的方法或者函数都存放在栈上,由高地址向低地址,向下扩展

内存管理方案
ios管理系统针对不同的场景提供不同的内存管理方案。

·TaggedPointer:对一些小对象使用,如NSNumber

·NONPOINTER_ISA:非指针型的ISA;应用于64位架构下的iOS应用程序。在64位架构下,isa指针占64个比特位,实际上有32位或者40位就够用了,剩余的比特位就浪费了。为了不让内存浪费更好的管理内存,剩余的32位苹果用来存储和内存管理相关的内容。

·散列表:是一个复杂的数据结构,其中包含了引用计数表和弱引用表。

【详解NONPOINTER_ISA】

在64位架构下:

第0位叫indexed的标志位,如果是0,代表它是一个isa指针,表示当前对象的类对象的地址;如果是1,代表它不仅是一个isa指针,当前对象的类对象的地址,还存储内存管理相关的内容。

第一位has_assoc表示当前对象是否有关联对象,0表示没有,1表示有。

第二位has_cxx_dtor代表当前对象是否有c++代码

第三位 3···31、32···35到第35位共33位,表示当前对象的类对象的内存地址。

第36···41位共6位,是magic 字段。

第42位weakly_referenced表示是否含有弱引用指针。

第43位deallocating表示当前指针是否正在进行dealloc操作。

第44位has_sidetable_rc表示当前isa指针的引用计数是否达到上限,如果达到上限需要外挂一个sidetable,来额外存储相关的引用计数内容。

第45···63位extra_rc表示额外的引用计数,储存内存管理相关的,当引用计数很小的时候,就直接存在isa指针当中。

如下图:  

【详解sidetable】

散列表是通过SideTables()结构来实现的,sidetables下面挂了很多sidetable,在不同的架构下是有不同个数的,比如说在非嵌入式系统中sidetable有64个。

sideTables()实际上是一个哈希表(hash),可以通过它的对象指针,找到它对应的引用计数表或者弱引用表具体在哪个sidetable中。

sidetable有自旋锁(spinlock_t),引用计数表(refcountMap)和弱引用表(weak_table_t)。

sideTable结构:

自旋锁:是忙等的锁。如果锁已经被其他线程获取,那么当前线程会自己去不断的获取是否被释放,直到其他线程释放。适用于轻量访问。如+1,-1。

引用计数表:是hash表,其实就是hash查找,插入和查找通过同一个hash函数,避免了循环遍历,提高了查找效率。

size_t实际上是一个无符号long型(unsign long)的变量。在获取对象的真实的引用计数值时,需要向右偏移两位。

弱引用表:weak_table_t也是一个hash表。

思考如下问题:

为什么不是一个sidetable?而是有多个sidetable组成一个sideTables;或者说sidetables为什么是多张表,而不是一张表?

解析:

假设只有一张sidetable表,那么内存中的所有对象的引用计数或者弱引用都存储在这张表中,这个时候,如果我们要对某一个对象的引用计数值进行操作,+1或者-1;由于不同的对象在不同的线程中,不同的线程操作同一张表,就有资源访问的问题,那么我们要对这张大表进行加锁操作来保证数据访问的安全性。在这个过程中就会产生一个效率问题,比如,成千上万的对象进行引用计数操作,那么需要加锁排队,就会有效率问题。比如,现在已经有一个对象在操作这个大表,那么下个对象就要等前对象操作结束,把锁释放之后,它才能操作这张表。系统为了解决这种效率问题,引入了分离锁。分离锁就是把一个大表分成几个小表,A、B分别在不同表中,同时进行操作的话,可以并发进行,这样就提高了访问效率。

思考如下问题:

怎样实现快速分流?找到当前对象在哪张表中?【快速分流指给出一个对象的指针,如何快速的定位到这个这个对象在哪张表中】

解析:

sidetables本质是一张Hash表。

什么是Hash表?有一个指针对象key,通过hash函数的运算,得到一个值value,找到对应的sidetable。

思考如下问题:

你是否使用过自旋锁,自旋锁和普通锁有什么区别?适用于哪些场景?

解析:

自旋锁是忙等的锁,适用于轻量访问。

思考如下问题:

引用计数表示通过什么实现的?为什么引用计数表要用hash表来实现呢?

解析:

是通过hash表实现的。插入和查找都通过同一个hash函数,避免了循环遍历,提高了查找效率。

关于内存管理的讨论全部基于objc-runtime-680版本讲解。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值