窥探枚举的内存
- 我们先来看一个枚举,代码如下,初始化一个枚举之后,打印变量
memory
的内存地址,以便窥探内存究竟是如何存放数据的。
enum TestMemory{
case test1(Int,Int,Int)
case test2(Int)
case test3(Bool)
case test4
}
初始化一个枚举,关联值是4,5,6
var memory = TestMemory.test1(4, 5, 6)
这句代码是打印变量memory的内存地址,打印出来是0x0000000100008208
print(Mems.ptr(ofVal: &memory))
- 接下来我们用Xcode的View Memory功能(View Memory从这里找:Xcode-Debug-Debug Workflow-View Memory),查看一下
memory
变量的内存存储了什么,如下图所示,我们看到了我们初始的4、5、6的值已经在内存里了
memory的内存
- 我们想要知道枚举的内存,就得知道
memory
实际上用了多少个字节的内存,我们用以下代码来查看,通过打印我们可以得知,分配了32个字节的内存给memory
,而memory
实际上只用到了25个字节,字节对齐是8。
查看memory实际占用了多少个字节
print(MemoryLayout<TestMemory>.size) 实际占用了25个字节
查看memory分配了占用了多少个字节
print(MemoryLayout<TestMemory>.stride) 分配了32个字节
查看TestMemory的字节对齐数
print(MemoryLayout<TestMemory>.alignment) 字节对齐是8
- 那么我们回到View Memory中,我们可以看出前24个字节的内存是这样的
04 00 00 00 00 00 00 00、05 00 00 00 00 00 00 00、06 00 00 00 00 00 00 00
,由于是小端模式,所以读取的时候是00 00 00 00 00 00 00 04 、00 00 00 00 00 00 00 05 、00 00 00 00 00 00 00 06
,也就是咱们初始化时候存放的4、5、6;后面8个字节是00 00 00 00 00 00 00 00
,这32个字节,就是分配给memory
的32个字节,通过上面的打印,我们知道了memory
实际只占用了25个字节,前24个字节是我们存放的关联值,第25个字节是00
,这里我可以告诉大家,第25个字节存放的就是成员值,用来区分我们的变量时哪个成员;剩余的7个字节没有作用。
- 我们来验证一下第25个字节究竟是做什么的,将上述代码修改一下,重新用View Memory看一下内存,内存就变成了下图的样子:
枚举不变,只是将memory变成test2
var memory = TestMemory.test2(7)
print(Mems.ptr(ofVal: &memory))
test2时的内存
- 从上图中,我们可以看出来前8个字节是我们存放的7,再往后8个字节是0,再往后8个字节也是0,第25个字节存放的是1,这就验证了我们刚才的说法,第25个字节存放的是成员值,当memory是第一个成员时存放0,当memory是第二个成员时存放1,当memory是test3时肯定就会变成2,当memory是test4时肯定就会变成3。以下是这两种情况下的内存,可以完美验证我刚才的说法
memory = .test3(true)
print(Mems.ptr(ofVal: &memory)) 打印memory的内存地址
memory = .test3(true)时的内存
memory = .test4
print(Mems.ptr(ofVal: &memory)) 打印memory的内存地址
memory = .test4时的内存.png
-
- 以上就是窥探枚举内存的步骤,现在我们来总结一下:
-
枚举中会有1个字节存储成员值,用来区分变量是哪个枚举成员
-
枚举中会有N个字节存储关联值,N是占用内存最大的关联值,任何一个case都会共用这个N个字节。
-
例如今天这个例子中,关联值最大的是test1,关联了3个Int类型,每个Int占用8个字节,一共就是24个字节,剩下的test2、test3、test4都会共用这个24个字节;还有1个字节代表成员值,所以memory
实际上占用了25个字节。(与print(MemoryLayout<TestMemory>.size)打印出来的一致,互相验证了我们的说法)
网友评论