iOS开发总结(二)内存管理

243 阅读6分钟

内存管理

iOS内存管理方式


1、 Tagged Pointer(小对象)专门用来存储小的对象,
例如 
NSNumber 和 NSDate Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。
所以,它的内存并不存储在堆中,也不需要 malloc 和 free 在内存读取上有着 3 倍的效率,创建时比以前快 106 倍 objc_msgSend 能识别 Tagged Pointer,比如 NSNumber 的 intValue 方法,直接从指针提取数据 使用 Tagged Pointer 后,指针内存储的数据变成了 Tag + Data,也就是将数据直接存储在了指针中 NONPOINTER_ISA (指针中存放与该对象内存相关的信息) 苹果将 isa 设计成了联合体,在 isa 中存储了与该对象相关的一些内存的信息,原因也如上面所说,并不需要 64 个二进制位全部都用来存储指针。

2、NONPOINTER_ISA (指针中存放与该对象内存相关的信息) 苹果将 isa 设计成了联合体,在 isa 中存储了与该对象相关的一些内存的信息,原因也如上面所说,并不需要 64 个二进制位全部都用来存储指针

64位系统下)
第一位的 01 代表是纯地址型 isa 指针,还是 NONPOINTER_ISA 指针。
第二位,代表是否有关联对象
第三位代表是否有 C++ 代码。
接下来33位代表指向的内存地址
接下来有 弱引用 的标记
接下来有是否 delloc 的标记....等等

3.散列表(引用计数表、weak表)
  • SideTables 表在 非嵌入式的64位系统中,有 64张 SideTable
  • 每一张 SideTable 主要是由三部分组成。自旋锁引用计数表弱引用表
  • 全局的 引用计数 之所以不存在同一张表中,是为了避免资源竞争,解决效率的问题。
  • 引用计数表 中引入了 分离锁的概念,将一张表分拆成多个部分,对他们分别加锁,可以实现并发操作,提升执行效率




  1. 什么情况使用weak关键字,相比assign有什么不同?

    • 什么情况使用 weak 关键字?

    在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性

    自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。在下文也有论述:《IBOutlet连出来的视图属性为什么可以被设置成weak?》

    • 不同点:

    weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。

    assign 可以用非 OC 对象,而 weak 必须用于 OC 对象



  2. 如何让自己的类用copy修饰符?如何重写带copy关键字的setter?

    • 若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。

      具体步骤:

      需声明该类遵从 NSCopying 协议

      实现 NSCopying 协议。该协议只有一个方法:

      - (id)copyWithZone:(NSZone *)zone;
      
      1

      注意:一提到让自己的类用 copy 修饰符,我们总是想覆写copy方法,其实真正需要实现的却是 “copyWithZone” 方法。

    • 重写带 copy 关键字的 setter,例如:

      - (void)setName:(NSString *)name {
          //[_name release];
          _name = [name copy];
      }
      

  3. 深拷贝与浅拷贝分别是什么?

    浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

    当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应该考虑以下两种情形:

    • 当函数的参数为对象时,实参传递给形参的实际上是实参的一个拷贝对象,系统自动通过拷贝构造函数实现;

    • 当函数的返回值为一个对象时,该对象实际上是函数内对象的一个拷贝,用于返回函数调用处。

    copy方法:如果是非可扩展类对象,则是浅拷贝。如果是可扩展类对象,则是深拷贝。

    mutableCopy方法:无论是可扩展类对象还是不可扩展类对象,都是深拷贝。

  4. @property的本质是什么?ivar、getter、setter是如何生成并添加到这个类中的?

    • @property 的本质是实例变量(ivar)+存取方法(access method = getter + setter),即 @property = ivar + getter + setter;

      “属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。

    • ivar、getter、setter 是自动合成这个类中的

      完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译 器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。在前例中,会生成两个实例变量,其名称分别为 _firstName 与 _lastName。也可以在类的实现代码里通过 @synthesize 语法来指定实例变量的名字.

  5. @protocol和category中如何使用@property

    • 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性

    • category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:objc_setAssociatedObject和objc_getAssociatedObject

  6. 使用CADisplayLink、NSTimer有什么注意点?BAD_ACCESS在什么情况下出现?

    CADisplayLink、NSTimer会造成循环引用,可以使用YYWeakProxy或者为CADisplayLink、NSTimer添加block方法解决循环引用

  7. iOS内存分区情况

  8. 循环引用

  9. ARC 的 retainCount 怎么存储的?

  10. ARC 在编译时做了哪些工作?