KM的博客.

Swift内存布局初探

字数统计: 645阅读时长: 2 min
2022/03/25

Swift内存布局初探

enum

问题实际分配内存为何是25?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
///带有关联值的枚举
enum TestEnum {
case t1(Int, Int, Int)
case t2(Int, Int)
case t3(Int)
case t4(Bool)
}
print(MemoryLayout<TestEnum>.alignment)//Int类型内存对齐:8
print(MemoryLayout<TestEnum>.size)//实际大小:24 + 1
print(MemoryLayout<TestEnum>.stride)//系统分配:24 + 8


///带有关联值的枚举
enum Password {
case num(Int, Int)
case str
}
print(MemoryLayout<Password>.alignment)//Int类型内存对齐:8
print(MemoryLayout<Password>.size)//实际大小:16 + 1
print(MemoryLayout<Password>.stride)//系统分配:16 + 8

Struct

实际分配内存是多少?实际大小是多少?

1
2
3
4
5
6
7
8
9
10
11
///结构体
struct Point {
let x: Int
let y: Int
var isHit: Bool
}


print(MemoryLayout<Point>.alignment)//Int类型内存对齐:8
print(MemoryLayout<Point>.size)//实际大小:16 + 1
print(MemoryLayout<Point>.stride)//系统分配:16 + 8

Class的内存管理

Class 本身也是分配在栈上,在堆上保留class的type信息,type信息里面有一个函数表,class的函数在派发时会按照type信息里面的函数表进行派发。

当子类需要继承父类时,子类只要在自己的type信息中记录自己的信息即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
///分析Class1
var name = "Jack"
print(Mems.size(ofVal: &name)) // 16对齐
class Man {
// metadata 8 类型信息
// RefCounts 8 引用计数
var name = "j" // 16 字符串变量对齐
}
// 变量 size 接收类Size
var man = Man()
print(class_getInstanceSize(type(of: man))) // 32
print(class_getInstanceSize(Man.self)) // 32
print(Mems.size(ofRef: man)) // 示例对象实际分配:32


//分析Class2
var isMan = true
print(Mems.size(ofVal: &isMan)) // 1
class Man2 {
// metadata 8 类型信息
// RefCounts 8 引用计数
var isMan = true // 1 对齐
}
// 变量 size 接收类Size
var man2 = Man2()
print(class_getInstanceSize(type(of: man2))) //Class 16 + 8内存对齐
print(class_getInstanceSize(Man2.self)) //Class 16 + 8内存对齐
print(Mems.size(ofRef: man2)) // 实例对象:16 + 16 内存对齐

协议的内存管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protocol DragonFire {}
extension DragonFire {
func fire() {

}
}

struct YellowDragon: DragonFire {
let year = "8"
let teeth = 48
}

print(MemoryLayout<YellowDragon>.size) // 24
print(MemoryLayout<DragonFire>.size) // 40

协议类型内存管理使用Existential Container 内存模型。

前三个word使用Value buffer 来存储inline的值

第四个word使用Value Witness Table 存储各种操作如allocate、copy、destruct、deallocate等

第五个word使用Protocol Witness Table 来存储协议的函数

泛型的内存管理

泛型采用是和Exsistential Container原理类似的内存管理。

Value Witness Table 和 Protocol Witness Table是作为隐形参数传递到泛型方法里。

不过经过编辑器的层层inline优化后,最终类型会被推导出来,也就不再需要Existential Container 这一套方法了。

CATALOG
  1. 1. Swift内存布局初探
    1. 1.1. enum
    2. 1.2. Struct
    3. 1.3. Class的内存管理
    4. 1.4. 协议的内存管理
    5. 1.5. 泛型的内存管理