一、内存布局
内存布局.png- 代码段(_TEXT):程序代码
- 数据段(_DATA):
* 字符串常量:比如NSString *str = @"123";
* 已初始化数据(data):已初始化的全局变量等
* 未初始化数据(bss):未初始化的全局变量等
- 栈(stack):函数调用开销,比如局部变量。分配的内存空间地址越来越小
- 堆(Heap):通过alloc、malloc、calloc等动态分配的空间,分配的内存空间地址越来越大
二、深拷贝和浅拷贝
深拷贝:内存拷贝
浅拷贝:指针拷贝
集合类深拷贝通过归档、解档实现
三、MRC & ARC
MRC:
alloc, retain , release, retainCount autorelease, dealloc
ARC(自动引用计数):
- ARC 是LLVM和Runtime协作的结果
- ARC中禁止手动调用alloc/retain/release/retainCount/dealloc
- ARC中新增了weak,strong属性关键字
四、内存管理方案
1、TaggedPointer:
* 用于优化NSNumber、NSDate、NSString等小对象的存储
* 在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值
* 使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中
* 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
* objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销
* 如何判断一个指针是否为Tagged Pointer?
iOS平台,最高有效位是1(第64bit)
Mac平台,最低有效位是1
2、NONPOINTER_ISA(64位系统下)
* nonpointer
0:代表普通的指针,存储着Class、Meta-Class对象的内存地址,
1:代表优化过,不仅有类对象的地址,还有些内存管理方面的数据
* has_assoc:代表是否有关联对象,如果没有,释放时会更快
* has_cxx_dtor:是否有 C++ 代码,如果没有,释放时会更快
* shiftcls:存储着Class、Meta-Class对象的内存地址信息
* magic:用于在调试时分辨对象是否完成初始化
* weakly_referenced:是否有弱引用标记,如果没有,释放时会更快
* deallocating:对象是否正在释放
* has_sidetable_rc:
1、0表示引用计数是否过大无法存储在isa中
2、1表示应用计数存储在sizetable数据结构中(散列表)
* extra_rc: 额外的引用计数,当引用计数比较小的时候存储在这个地方,而不是存储在散列表中
3、散列表(引用计数表、weak表)
* SideTables表在非嵌入式的64位系统中,有 64张 SideTable 表
* 每一张 SideTable 主要是由三部分组成。
1、Spinlock_t(自旋锁)
2、RefcountMap(引用计数表)
3、weak_table_t(弱引用表)
为什么不是一个SideTable,二是一个SideTables组成的结构呢?
* 一张表,一个是效率问题,一个是多线程资源竞争问题
* 分离锁:将一张表分拆成多个表,对他们分别加锁,可以实现并发操作,提升执行效率
怎么实现快速分流?
给定对象内存地址,对哈希的值进行求余操作,目标是SideTables的数组的下表索引
Spinlock_t(自旋锁):
* 是 “忙等” 的锁
* 适用轻量访问
RefcountMap(引用计数表):
是用哈希表实现的,目的是提高查找效率,插入或获取是通过同一个函数来实现的
size_t:
* 第一位weakly_referenced: 是否有弱引用
* 第二位deallocating:对象是否在dealloc
* 其他的是值实际的引用计数值。
weak_table_t(弱引用表):
弱引用技术表.png
是用哈希表实现的,目的是提高查找效率,插入或获取是通过同一个函数来实现的
网友评论