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的原因。
