OC经验-鸡肋

631 阅读2分钟

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。