谈谈Swift中的枚举内存布局

在掘金上看到从 汇编 到 Swift 枚举内存 的惊鸿一瞥以后,做者分析了几种不一样枚举的内存布局,可是我感受覆盖的不够全面,算是对做者那篇文章的一个补充。建议先看下做者的文章,做者的结论以下:git

关联值枚举: 最大字节数之和 额外 + 1 最后一个字节 存放 case 类型 非关联值枚举: 内存 占用 1个字节 内存中 如下标数 为值,依次累加github

疑问

不知道你看完以后,有没有我一样的疑问?bash

  1. 普通枚举时,内存占用一个字节,而一个字节最多只能从0到255,那么当case的选项超出256个时,会怎样
  2. 若关联值得类型是协议,结构体,类或其余枚举呢?这个时候内存占用是怎么样的
  3. 若是是递归枚举呢?

答案

  • 普通枚举,测试代码和结果以下说明测试代码中的show函数会打印,枚举的地址,内存和大小,从复制Mems
func test(){
     enum TestEnum {
       case testCase1
       case testCase2
    }
   var testEnum = TestEnum.testCase1
   show(val: &testEnum)
   testEnum = .testCase2
   show(val: &testEnum)
}
复制代码

  • 当case选项过多超出256个时,好比出现300个时,会占用2个字节,因为超出2个字节须要的case太多,我没有进行测试,但应该是依次类推的
//测试case过多时
func test1(){
    var testEnum = MoreCaseEnum.case257
    show(val: &testEnum)
}
复制代码

  • 当关联值是结构体时,跟做者的结论同样
struct TestStruct: TestProtocol {
    var testPropetry1 = 10
    var testPropetry2 = 11
    var testPropetry3 = 12
    var testPropetry4 = 13
    var testPropetry5 = 14
}
func test2() {
    enum TestStructEnum {
        case testCase1
        case testCase2(TestStruct)
        case testCase3
    }
    var testEnum = TestStructEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestStruct())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
复制代码

  • 当关联值是class时,跟做者的结论不同,测试代码和结果以下 结论:枚举一共占用了8个字节,如果关联class的case,则存放对象的地址,其余的按照case的顺序赋值,此时是按照2*index赋值的,index为第几个无关联值的case
//测试关联值的类型是class
func test3() {
    enum TestClassEnum {
        case testCase1
        case testCase2(TestClass)
        case testCase3
    }
    var testEnum = TestClassEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
复制代码

  • 当关联值的类型class+bool(这里换成其余小于4个字节l的类型都同样,好比Int16,Int8)时 结论:枚举占用8字节,当关联值是对象是,存放的是对象的地址,不然,8字节的前半部分存放的是区分类型,后半部分存放的关联的值或者枚举的case的位置(具体的规则我没测出来)
func test4() {
    enum TestClassOtherEnum {
        case testCase1
        case testCase2(TestClass)
        case testCase3(Bool)
    }
    var testEnum = TestClassOtherEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase3(true)
    show(val: &testEnum)
}
复制代码

  • 关联值的类型是占用一字节的类型时,好比bool和其余无关联值枚举
    结论:枚举占用一个字节,前4位区分类型,后四位来表示具体的值
func test5() {
    enum TestEnum {
        case testCase1
        case testCase2
    }
    enum TestSamllEnum {
        case testCase1
        case testCase2(TestEnum)
        case testCase3(Bool)
    }
    var testEnum = TestSamllEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(.testCase2)
    show(val: &testEnum)
    testEnum = .testCase3(true)
    show(val: &testEnum)
}
复制代码

  • 关联值的类型是协议时 结论:枚举占用40个字节,最后一项是区分类型,对于关联值协议的case,若知足协议的是class时,第一项是class的地址,若知足协议的是struct时,当struct的占用空间不大于24时,则前三项存放的是结构体的值,不然把结构体的值存放到外部
func test6() {
    enum TestProtocolEnum {
        case testCase1
        case testCase2(TestProtocol)
        case testCase3
    }
    var testEnum = TestProtocolEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase2(TestStruct())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
复制代码

  • 枚举类型是递归枚举时 结论:此时占用空间一直是8
func test7() {
    indirect enum TestIndirectEnum {
        case testCase1
        case testCase2(TestIndirectEnum)
        case testCase3
    }
    var testEnum = TestIndirectEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(.testCase3)
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
复制代码

Other

以上全部的结论都是测试并总结出来,不能保证绝对的正确性,仅供参考,测试demo函数

参考连接

相关文章
相关标签/搜索