Swift枚举内存分析

517 阅读2分钟

思考

以下枚举在内存中占用多少空间?(以下都是在64bit的环境下)
enum TestEnum {
    case test1
}

enum TestEnum_1 {
    case test1
    case test2
    case test3
}

enum TestEnum_Int: Int {
    case test1
    case test2
}

enum TestEnum_Value {
    case test1(Int, Int)
}

enum TestEnum_Value_1 {
    case test1(Int, Int)
    case test2
    case test3
}

先来看一下内存布局打印的结果

MemoryLayout<TestEnum>.show()
MemoryLayout<TestEnum_1>.show()
MemoryLayout<TestEnum_Int>.show()
MemoryLayout<TestEnum_Value>.show()
MemoryLayout<TestEnum_Value_1>.show()

size:表示实际使用的内存
stride:表示分配的内存
alignment:表示对齐方式

Log:
=========TestEnum=========
  size:      0
 stride:     1
alignment:   1
=========TestEnum=========
=========TestEnum_1=========
  size:      1
 stride:     1
alignment:   1
=========TestEnum_1=========
=========TestEnum_Int=========
  size:      1
 stride:     1
alignment:   1
=========TestEnum_Int=========
=========TestEnum_Value=========
  size:      16
 stride:     16
alignment:   8
=========TestEnum_Value=========
=========TestEnum_Value_1=========
  size:      17
 stride:     24
alignment:   8
=========TestEnum_Value_1=========

通过打印可以看到,每种枚举类型,内存布局差异还是很大的。接下来一一分析一下。

TestEnum

实际使用内存为0,可以很容易想到,这个可能是一个常量。 image-20210726174815864.png image-20210726174423214.png

打上断点,通过汇编可以看到,确实是一个常量0x1。 当枚举只有一个的时候,枚举值已经可以看做是确定的了

TestEnum_1

当存在多个枚举值的时候,通过查看内存值可以看到,每个枚举值都有对应的类似编号的东西。而且从0开始编号。

image-20210726181406687.png image-20210726181659823.png

TestEnum_Int

我们都知道,swift的枚举,还可以指定原始值的类型和内容。比如在 TestEnum_Int 中,就表示这个枚举的原始值类型为Int,而且默认值是从0开始递增。

很容易就误认为,既然是Int类型,那么内存至少是8个字节。

通过下面的内存分析,来看一下 image-20210726202631540.png image-20210726181659823.png

实际上,这个跟TestEnum_1的情况是一样的。或许你会很疑惑,那这个原始值到底是存在哪里了?

因为原始值是固定的,也就是说是个常量。

所以伪代码应该有点像下面这样

if enum == 0x0 {
	return 原始值0
}

if enum == 0x1 {
	return 原始值1
}

TestEnum_Value

再来看看,swift的枚举的另外一个特性,附加值。

通过查看内存,可以看到,如果是2个附加值为Int类型的枚举,那么至少需要 2 * 8 = 16个字节的空间

image-20210726203001322.png image-20210726202938318.png

TestEnum_Value_1

上面已经看了,附加值至少是附加值类型所需的空间大小。但是只是说一个枚举值的情况下,如果是多个枚举值,那么应该就是对应枚举值的附加值所占空间最的那个枚举值 + 1 个字节(用来表示不同枚举值)。

内存分布如下图

image-20210726203134663.png image-20210726203729057.png

总结

  1. 只有原始值的枚举,所占的内存一般都是1个字节(如果1个字节不够放,我相信应该是2个字节,如果真有这么多的枚举值,可以考虑别的数据结构了,所以这里不进行验证)

  2. 如果有附加值,那么枚举值所占的空间,就是附加值所需最大的空间+ 1个字节