谈谈Swift中的枚举内存布局

黑客技术

点击右侧关注,了解黑客的世界!

Java开发进阶

点击右侧关注,掌握进阶之路!

Python开发

点击右侧关注,探讨技术话题!

作者丨李坤
链接:

https://juejin.im/post/5df4d98be51d45584c55322f

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

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

疑问

不知道你看完之后,有没有我同样的疑问?

  1. 普通枚举时,内存占用一个字节,而一个字节最多只能从0到255,那么当case的选项超出256个时,会怎样

  2. 若关联值得类型是协议,结构体,类或其他枚举呢?这个时候内存占用是怎么样的

  3. 如果是递归枚举呢?

答案

  • 普通枚举,测试代码和结果如下说明测试代码中的show函数会打印,枚举的地址,内存和大小

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

以上所有的结论都是测试并总结出来,不能保证绝对的正确性,仅供参考

参考链接

  • 从 汇编 到 Swift 枚举内存 的惊鸿一瞥

https://juejin.im/post/5de5fae1e51d4504b85cd15f?utm_source=gold_browser_extension#comment

  • Mems

https://github.com/CoderMJLee/Mems

 推荐↓↓↓ 

????16个技术公众号】都在这里!

涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。

万水千山总是情,点个 “在看” 行不行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值