7-6.【高级特性】class、struct、enum 的内存占用和对齐规则是什么?

3 阅读2分钟

一、Swift 内存布局的三条基本规则(先背)

  1. 对齐(Alignment)= 最大字段对齐
  2. Size = 字段 size + padding(向对齐取整)
  3. Stride = size 向 alignment 对齐后的结果

Swift 的 MemoryLayout<T> 就是这三件事。

MemoryLayout<T>.size
MemoryLayout<T>.alignment
MemoryLayout<T>.stride

二、struct 的内存占用与对齐

1️⃣ struct 的布局规则

  • 字段 按声明顺序排列
  • 不重排字段(和 C 不同)
  • 每个字段起始地址必须满足自身对齐
  • struct 整体对齐 = 最大字段对齐

2️⃣ 示例 1:padding 产生的原因

struct S {
    let a: Int8   // 1 byte
    let b: Int64  // 8 bytes
}

内存布局:

offset 0: a (1)
offset 1~7: padding
offset 8~15: b
  • size = 16
  • alignment = 8
  • stride = 16

3️⃣ 字段顺序影响内存

struct S2 {
    let b: Int64
    let a: Int8
}
offset 0~7: b
offset 8:   a
offset 9~15: padding
  • size = 16
  • 如果后面再接数组,会更省空间

👉 结构体字段顺序会影响 padding,进而影响 cache 友好性


三、enum 的内存占用与对齐(最容易被低估)

1️⃣ enum 的本质

enum =

payload(最大 case) + tag(区分 case)

enum E {
    case a(Int8)
    case b(Int64)
}

2️⃣ 内存布局规则

  • payload 大小 = 最大关联值 size

  • alignment = payload 的最大 alignment

  • tag:

    • 编译器尽量塞进 payload 的空闲位
    • 塞不下才额外占字节

3️⃣ 示例

enum E {
    case small(Int8)
    case big(Int64)
}
  • payload = Int64 (8 bytes)
  • tag 可利用 Int64 的空闲高位
  • 👉 size = 8,alignment = 8

但:

enum F {
    case a(Int64)
    case b(Int64)
}
  • payload = 8
  • tag 仍可能需要额外空间
  • size 仍然通常是 8(ABI 优化)

⚠️ enum 的布局是 最复杂、最依赖编译器优化的


四、class 的内存占用与对齐

1️⃣ class 对象的整体结构(堆上)

class C {
    var x: Int
    var y: Int8
}

对象内存大致是:

[ metadata / isa ]
[ refcount / runtime info ]
[ x ]
[ padding ]
[ y ]
[ padding ]

2️⃣ 关键点

  • 对象头(runtime header):

    • 指针大小(8 bytes)
    • ARC 管理信息
  • 实例属性按 struct 规则布局

  • 对齐通常是 8 或 16 字节

👉 class 的最小占用远大于 struct


3️⃣ 示例对比

struct S {
    let x: Int
}

≈ 8 bytes

class C {
    let x: Int
}

32~40 bytes(平台相关)

即使只有一个 Int,class 也很“重”


五、Stride 的真正含义(高频追问)

struct P {
    let a: Int8
}
  • size = 1
  • alignment = 1
  • stride = 1
struct Q {
    let a: Int8
    let b: Int64
}
  • size = 16
  • alignment = 8
  • stride = 16

📌 数组中元素之间的间距 = stride


六、一张总表(面试直接用)

类型对齐规则内存占用特点
struct最大字段对齐padding 受字段顺序影响
enum最大 payload 对齐payload + tag(高度优化)
class对象头 + 属性对齐堆分配,最重

七、终极面试总结(建议原话)

struct 按字段顺序布局,对齐取最大字段;
enum 是最大 payload 加 tag,并尽量压缩;
class 在堆上,包含对象头和 ARC 信息,内存占用显著更大。