一、Swift 内存布局的三条基本规则(先背)
- 对齐(Alignment)= 最大字段对齐
- Size = 字段 size + padding(向对齐取整)
- 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 信息,内存占用显著更大。
英文版
7-6. [Advanced] What are the Memory Occupancy and Alignment Rules for Class, Struct, and Enum?
I. The Three Fundamental Rules of Swift Memory Layout (Memorize These)
- Alignment = The alignment of the largest field within the type.
- Size = The sum of field sizes + padding (rounded to meet internal alignment).
- Stride = The distance between two instances of the type in an array (Size rounded up to the nearest multiple of Alignment).
Swift’s
MemoryLayout<T>provides these three metrics.
Swift
MemoryLayout<T>.size // Actual contiguous bytes used
MemoryLayout<T>.alignment // Addressing requirement (e.g., 8-byte boundary)
MemoryLayout<T>.stride // Step-size in an array
II. Struct: Memory Occupancy and Alignment
1️⃣ Layout Rules
- Fields are laid out in the order they are declared.
- No field reordering (unlike some optimizations in other languages).
- Each field's starting address must satisfy its own alignment.
- The struct's overall alignment = The largest alignment among its fields.
2️⃣ Example 1: Why Padding Occurs
Swift
struct S {
let a: Int8 // 1 byte, alignment 1
let b: Int64 // 8 bytes, alignment 8
}
Memory Layout:
- Offset 0:
a(1 byte) - Offset 1~7: Padding (to align the next 8-byte field)
- Offset 8~15:
b(8 bytes) - Size: 16 | Alignment: 8 | Stride: 16
3️⃣ Field Order Affects Memory
Swift
struct S2 {
let b: Int64 // 8 bytes
let a: Int8 // 1 byte
}
Memory Layout:
- Offset 0~7:
b - Offset 8:
a - Offset 9~15: Tail Padding (to satisfy the 8-byte alignment for the next element in an array)
- Size: 9 | Alignment: 8 | Stride: 16
👉 Field order impacts padding, which in turn affects cache-friendliness and total memory footprint.
III. Enum: Memory Occupancy and Alignment (Often Underestimated)
1️⃣ The Essence of an Enum
An Enum = Payload (Largest Case) + Tag (To distinguish cases) .
2️⃣ Layout Rules
-
Payload Size = The size of the largest associated value.
-
Alignment = The maximum alignment of any payload.
-
Tag:
- The compiler attempts to nest the tag into spare bits (extra inhabitants) of the payload.
- If the payload has no spare bits, an extra byte is appended.
3️⃣ Example
Swift
enum E {
case small(Int8)
case big(Int64)
}
- Payload:
Int64(8 bytes) - Tag: Can utilize the spare high-bits of the
Int64. - Size: 8 | Alignment: 8
⚠️ Enum layout is highly complex and heavily dependent on ABI (Application Binary Interface) optimizations.
IV. Class: Memory Occupancy and Alignment
1️⃣ The Class Object Structure (On the Heap)
Swift
class C {
var x: Int
var y: Int8
}
The heap memory roughly looks like:
[ Metadata / isa pointer ](8 bytes)[ Refcount / Runtime Info ](8 bytes)[ x ](8 bytes)[ y ](1 byte)[ Padding ](7 bytes)
2️⃣ Key Points
- Runtime Header: Includes the pointer (8 bytes) and ARC management info.
- Instance Properties: Laid out according to the same rules as structs.
- Alignment: Usually 8 or 16 bytes depending on the platform.
👉 The overhead of a class is significantly higher than a struct.
3️⃣ Comparison Example
- Struct with one Int: ≈ 8 bytes.
- Class with one Int: ≈ 32–40 bytes (Platform dependent).
Even with a single field, a
classis "heavy" due to its metadata and heap management.
V. The True Meaning of Stride (Common Interview Follow-up)
Swift
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 = The distance between elements in an array. If you have [Q], the CPU jumps 16 bytes to find the next a, even though the data only technically occupies 9 bytes of "meaningful" space (plus internal padding).
VI. Summary Table
| Type | Alignment Rule | Occupancy Characteristics |
|---|---|---|
| Struct | Max field alignment | Padding is sensitive to field order. |
| Enum | Max payload alignment | Payload + Tag (Highly optimized/compressed). |
| Class | Header + Property alignment | Heap allocated; contains metadata/ARC (Heavy). |
VII. Ultimate Interview Summary
Structs are laid out by field order, aligned to the largest field. Enums consist of the largest payload plus a tag, which the compiler tries to compress. Classes reside on the heap and include an object header and ARC information, making their memory footprint significantly larger than value types.