Any metadata的内存布局是怎样的?

摘要:Swift中enum、struct、class、protocol都有对应的metadata。 metadata用来描述上述这些类型本身,这点和OC的元类有点类似。 1 直观感受 metadata 假设用下面代码定义了一个enum: enum
Swift中enum、struct、class、protocol都有对应的metadata。 metadata用来描述上述这些类型本身,这点和OC的元类有点类似。 1 直观感受 metadata 假设用下面代码定义了一个enum: enum Direction { case top case left case bottom case right } 经过编译链接之后,上面的enum Direction以及对应的metadata都写入到了对应的Mach-O文件中。 假设编译链接之后的Mach-O文件名为A,那么,使用下面命令就可以查看enum Direction以及对应metadata的位置: nm -n A | xcrun swift-demangle | grep -i Direction nm 命令读取Mach-O中的所有符号信息。 swift-demangle对已经mangle的swift符号名进行demangle。 输出的结果如下: 000000000001e004 s _symbolic _____ 7iOSTest9DirectionO 0000000000020820 s full type metadata for iOSTest.Direction 0000000000020830 S type metadata for iOSTest.Direction 第1列的数字代表对应项在Mach-O文件中的偏移。 输出的第1行的符号名7iOSTest9DirectionO有点怪。 这是因为swift-demangle没有彻底demangle干净,我们再次手动demangle下: xcrun swift-demangle s7iOSTest9DirectionO 注意我们在符号名字前加了一个小写字母s。 Swift会在mangle名前加一个字母s,代表Swift。 再次demangle的输出结果为: $s7iOSTest9DirectionO ---> iOSTest.Direction 可以看到,它正是enum Direction本身,位于0x1e004。 输出第3行可以看到enum Direction的metadata位于0x20830。 输出的第2行还有一个full type metadata,这是什么呢? 在Swift里,一个类型的metadata前面根据类型的不同,会有一些其他数据。 其中任何类型都有一个数据是value witness table指针。 value witness table是Swift用来管理类型的生命周期,比如怎么复制、怎么销毁。 可以看到,所谓的full type metadata就是「其他数据」+对应的type metadata。 而我们平时使用的.self语法,得到的就是metadata本身: (lldb) p unsafeBitCast(Direction.self, to: UnsafeRawPointer.self) (UnsafeRawPointer) 0x100adc830 (lldb) p/x 0x100adc830 - 0x0000000100abc000 (Int) 0x0000000000020830 从上面lldb的输出看到,经过ASLR的调整,Direction.self的位置正是0x20830。 2 Any 的 metadata Any是一个protocol,如下面输出: (lldb) p Any.self (Any.Protocol) Any Any还是一个空协议组合,表示「没有任何要求」。 而「没有任何要求」是任何类型都满足的,这也是任何类型都能转成Any的原因。
阅读全文