这是我参与「第四届青训营 」笔记创作活动的的第5天。
今天整理了上课的系统内存管理部分,内存管理一直是我学习的不够透彻的部分,明日继续深入学习。
Objective-C内存管理
背景介绍
Heap & Stack
-
Stack(栈)
-
Pop(销毁)➕ Push(存储)
-
存储参数/局部变量/函数调用后返回地址,线程安全
-
Stack Pointer
- 指向栈顶
- 一般存储在寄存器
-
高地址向低地址扩展
-
-
Heap(堆)
- 与Heap数据结构无关
- 手动分配
- 向高地址扩展
- 存储数组和对象,线程共享
C内存管理
malloc➕free
C++内存管理
- new➕delete
-
malloc➕free与new➕delete
-
malloc/free只是动态分配内存空间/释放空间
new/delete 还会调用构造函数和析构函数进行初始化与
-
malloc/free需要手动计算类型大小
new/delete可自动计算类型的大小
-
malloc/free管理内存失败会返回0
new/delete等的方式管理内存失败会抛出异常。
-
-
Smart Pointer 智能指针
🌟保留 -> 和 * 运算符
🌟auto_pt & unique_ptr
- 两个指针不能指向同一个资源
- 无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
🌟shared_ptr
可以复制赋值操作 创造对象(control block中的引用计数)
Reference Counting 引用计数
- 记录了当前内存资源到底有多少指针在引用(可以访问这个资源)
- 当新增加一个可以访问这个资源的引用,计数器会加1,反之会减去1
- 当引用计数= 0时, 对象会被销毁
iOS内存管理
核心是管理(强)引用计数 (Reference Counting)
当前代码只需要考虑ARC
管理什么?
- 继承NSObject对象会分配在堆里面
- 任何继承NSObject对象都需要内存管理
为什么要管理?
- 多个对象之间相互强引用,导致不能释放,无法让系统回收
- 如果一个程序占用内存过多,系统可能会强制关闭程序,造成crash
- 如果提前释放指针,会导致野指针,也会造成crash
术语:持有 = retain = 引用计数 +1 释放 = release = 引用计数 -1
MRC Manual Reference Counting
OC中,使用引用计数来进行内存管理,每个对象都有一个相应的引用计数
- “alloc”, “new”, “copy”, or “mutableCopy” 开头的方法创建的对象,引用计数 = 1
- 当持有(retain)一个对象,这个对象的引用计数就会递增(+1)
- 当这个对象的某个持有被释放(release),这个对象的引用计数就会递减(-1)
- 当这个对象的引用计数变为0,那么这个对象就会被系统回收,系统向对象发送dealloc【不能直接调用 dealloc】
Autorelease-Pool(自动释放池)
- 对象会放到自动释放池,统一释放
-
autorelease和release的区别是:
- release是马上释放对某个对象的强引用;
- autorelease是延迟释放某个对象。
- 在部分场景下,使用Autorelease pool可以降低内存峰值
ARC(Automatic Reference Counting)
编译器自动加入内存管理代码
-
retain/release都不用考虑
- 只需要初始化的时候 [NSObject alloc] init]
- 可以自定义 dealloc
- 只需要负责对象的创建即可
- 不需要手动维护引用计数
-
只要有一个强指针在内存指向对象,对象就不能释放
- ARC 销毁时机是强引用的个数 = 0
- 而不是引用计数 = 0
-
默认所有对象变量的指针都是强指针
- 弱指针需显式声明