iOS程序的内存布局
- 代码段:编译之后的代码
- 数据段
- 字符串常量:比如NSString *str = @"123";
- 已初始化的数据:已初始化的全局变量、静态变量等
- 未初始化的数据:未初始化的全局变量、静态变量等
- 堆:通过alloc、malloc、calloc等动态分配的空间,分配的内存空间地址越来越大
- 栈:函数的调用开销,比如函数中的局部变量,分配的内存空间地址越来越小
Tagged Pointer
-
从64bit开始,iOS引入了
Tagged Pointer
技术,用于优化NSNumber、NSDate、NSString等小对象的存储 -
在没有使用
Tagged Pointer
之前,NSNumber等对象需要动态分配内存、维护引用计数
等,对象指针存储的是堆中对象的地址值 -
使用
Tagged Pointer
之后,NSNumber指针里面存储的数据变成了:Tag+Data
,也就是将数据直接存储到了指针中,其中tag
用来标示类型是NSString、NSNumber还是其他。当指针不够存储数据时,才会使用动态分配内存的方式来存储数据。
NSNumber *number = [NSNumber numberWithInt:10];
-
objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节约了调用开销。
-
iOS平台指针最高位(从右数第64位)是1,这个指针就是Tagger Pointer。
-
Mac平台,最低有效位是1的指针是Tagger Pointer。
copy
- 拷贝的目的:产生一个副本对象,跟源对象
互不影响
。修改了源对象,不会影响副本对象;修改了副本对象,不会影响源对象。 - iOS提供了两个拷贝方法
- copy:不可变拷贝,产出不可变副本
- mutableCopy:可变拷贝,产生可变副本
- 深拷贝、浅拷贝
- 浅拷贝:不拷贝对象本身,不产生新的对象,只对指向对象的指针进行拷贝,新的对象指针还指向老的对象
- 深拷贝:拷贝对象本身,在内存中新生成一个对象,新的对象指针指向新生成的对象
自定义对象要想被copy,得准守NSCopying
协议
@interface Person : NSObject<NSCopying>
@property(assign,nonatomic)int age;
@end
@implementation Person
- (id)copyWithZone:(nullable NSZone *)zone{
Person *p = [Person allocWithZone:zone];
p.age = self.age;
return p;
}
@end
weak指针的原理
- __strong:强指针,默认创建的都是强指针
- __weak:弱指针,指针指向的对象销毁后,该指针自动变成nil。
- __unsafe_unretained:不安全的弱指针,指针指向的对象销毁后,该指针还指向原来对象的地址,使用该指针会出现野指针错误。
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table; //弱引用的哈希表
}
对象销毁时,通过对象地址找到弱引用哈希表中指向该对象的所有弱指针,赋值成nil。