iOS内存管理 | 青训营笔记

78 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第5天

iOS内存管理

iOS 内存管理的核心是管理「(强)引用计数 (Reference Counting)」

在当前代码中,我们基本只用考虑 ARC

Objective C内存管理

  • 继承 NSObject 对象会分配在堆里面,任何继承 NSObject 对象都需要进行内存管理
  • 多个对象之间相互强引用,导致不能释放,无法让系统回收,如果一个程序占用内存过多,系统可能会强制关闭程序,造成crash,如果提前释放指针,会导致野指针,也会造成crash
  • 持有 = retain = 引用计数 +1
  • 释放 = release = 引用计数 -1

MRC (Manual Reference Counting)

  • OC 中,使用引用计数来进行内存管理。每个对象都有一个与其相对应的引用计数器,当持有一个对象,这个对象的引用计数就会递增;当这个对象的某个持有被释放,这个对象的引用计数就会递减。当这个对象的引用计数变为0,那么这个对象就会被系统回收
  • alloc, new, copy, 或者 mutableCopy 开头的方法创建的对象,引用计数 = 1
    // 使用了alloc分配了内存,obj指向了对象,该对象本身引用计数为1,不需要retain 
    id obj = [[NSObject alloc] init]; 
    // 使用了new分配了内存,objc指向了对象,该对象本身引用计数为1,不需要retain 
    id obj = [NSObject new];
    
  • 对一个对象发送 retain 消息,可以让对象的引用计数 +1,对一个对象发送 release 消息,可以让对象的引用计数 -1
  • 当对象的引用计数为 0 时,即将销毁的时候,系统会向对象发送一条dealloc消息 (不能直接调用 dealloc)
  • Autorelease-Pool
    • 对象会放到自动释放池,统一释放
    • autoreleaserelease 的区别:
      • release 是马上释放对某个对象的强引用
      • autorelease 是延迟释放某个对象
    • 在部分场景下,使用Autorelease pool可以降低内存峰值

ARC (Automatic Reference Counting)

  • retain/release都不用考虑
    • 只需要初始化的时候 [NSObject alloc] init]
    • 可以自定义 dealloc
  • 只要有一个强指针在内存指向对象,对象就不能释放
    • ARC 销毁时机是强引用的个数 = 0,而不是引用计数 = 0
  • 默认所有对象变量的指针都是强指针,弱指针需显式声明
    __weak Person *p2 = [Person new];
    

内存管理实例

@property

@property(属性):属性不仅是类的成员变量,还生成了属性的 setter getter方法

  • @property 修饰符
    • strong:拥有属性对象,强持有,只有 OC 对象才能使用该属性
    • weak: 不拥有属性对象,弱持有,只有 OC 对象才能使用该属性
      • strong 区别:setter 内部会调用 copy 方法
    • assign: 指定 setter 使用简单赋值
      • 一般用于simple types, e.g. 基本类型/NSInteger/CGRect
      • default 修饰符

weak 销毁与我无关,strong 我销毁它才会销毁

循环引用

浅拷贝 v.s. 深拷贝 可变 v.s. 不可变

深浅拷贝 Shallow/Deep Copy

可变不可变

  • 两种类两种行为
    • 不可变对象
      • copy
      • mutableCopy
    • 可变对象
      • copy
      • mutableCopy

不可变到不可变的copy是浅拷贝,其他3种情况是深拷贝

  • 内存问题引起 Crash
    • 野指针
      • 当所指向的对象被提前释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的野指针,则将产生无法预料的后果,因为此时野指针所指向的内存现在包含的已经完全是不同的数据
    • OOM (Out Of Memory)
      • 指的是在 iOS 设备上当前应用因为内存占用过高而被操作系统强制终止