7-1.【高级特性】值类型和引用类型在内存布局和 ARC 管理上有何差异?

3 阅读2分钟

一、内存布局上的差异

1️⃣ 值类型(Value Type)

典型代表structenumtuple、基本类型(IntDouble

📦 内存存储方式

  • 直接存储数据本身

  • 通常分配在:

    • 栈(Stack) —— 局部变量
    • 或作为成员嵌入到其它对象的内存中
  • 不需要额外的间接层

struct Point {
    var x: Int
    var y: Int
}

let p = Point(x: 1, y: 2)
// p 的 x、y 连续存放在一块内存里

🧠 特点

  • 内存布局连续、紧凑
  • 访问速度快(无指针跳转)
  • 拷贝语义明确(copy)

Swift 的标准库值类型(如 ArrayDictionary)内部会用 堆 + 引用计数
对外仍然表现为值语义(Copy-on-Write)


2️⃣ 引用类型(Reference Type)

典型代表classactor

📦 内存存储方式

  • 对象本体分配在堆(Heap)

  • 变量中存的是:

    • 一个 指向堆对象的引用(指针)
class Person {
    var name: String
}

let a = Person(name: "Tom")
let b = a

内存关系是:

a ──┐
    ├──> Heap 上的 Person 对象
b ──┘

🧠 特点

  • 多个变量可指向同一对象
  • 内存分配 / 释放成本更高
  • 访问需要一次指针间接访问

二、ARC 管理机制上的差异

1️⃣ 值类型:❌ 不参与 ARC

  • 没有引用计数

  • 生命周期由:

    • 作用域结束
    • 栈帧销毁
    • 或宿主对象释放
  • 拷贝时直接复制值(或触发 COW)

var a = 10
var b = a
b = 20
// ab 完全独立

不存在循环引用问题


2️⃣ 引用类型:✅ 由 ARC 管理

ARC(Automatic Reference Counting)负责:

  • 跟踪对象被多少“强引用”持有
  • 引用计数为 0 时释放对象

📌 引用规则

  • strong:默认,+1
  • weak:不增加引用计数,可自动置 nil
  • unowned:不增加引用计数,但不为 nil(有风险)
class A {
    var b: B?
}

class B {
    weak var a: A?
}

⚠️ 典型问题:循环引用

class A {
    var b: B?
}

class B {
    var a: A?
}
// AB,ARC 无法释放

必须用 weak / unowned 打破。


三、对比总结表(面试超好用)

维度值类型引用类型
代表struct / enumclass / actor
内存位置栈 / 内嵌
变量保存内容实际数据对象引用
语义拷贝语义共享语义
ARC 管理❌ 不参与✅ 参与
循环引用不存在可能存在
线程安全天然更安全需手动保证

四、一句话总结(面试必杀)

值类型直接存值、不走 ARC、生命周期简单;
引用类型存指针、由 ARC 管理、需要处理引用关系和循环引用问题。