今天有位群友抛出了一个很有意思的问题:为什么系统类的 class 地址比栈区变量更高?
image-20210519235852843
通常情况下,我们对进程内存的布局的印象是下面这种:
栈区在高地址,堆区和二进制内存区域在低地址
image-20210519233555128
但是,iOS 的进程布局将系统共享库的内存区域放到了栈区上面:
image-20210519234027973
下面,我们通过 lldb 验证一下:
14.3 (18C66)
(lldb) p/x [NSObject class]
(Class) $2 = 0x00000001ee523288 NSObject
(lldb) image lookup -va 0x1ee523288
Address: libobjc.A.dylib[0x00000001d9b13288] (libobjc.A.dylib.__DATA_DIRTY.__objc_data + 200)
Summary: (void *)0x00000001ee523260: NSObject
Module: file = "/Users/xxx/Library/Developer/Xcode/iOS DeviceSupport/14.3 (18C66)/Symbols/usr/lib/libobjc.A.dylib", arch = "arm64"
Symbol: id = {0x00000027}, range = [0x00000001ee523288-0x00000001ee5232b0), name="NSObject", mangled="OBJC_CLASS_$_NSObject"
(lldb) p/x [ViewController class]
(Class) $3 = 0x0000000104d41408 ViewController
(lldb) image lookup -va 0x104d41408
Address: slsls[0x000000010000d408] (slsls.__DATA.__objc_data + 0)
Summary: (void *)0x0000000104d41430: ViewController
Module: file = "/Users/xxx/Library/Developer/Xcode/DerivedData/S-Hy-gwrbrxhnpymmlggvtfdcfffgjpme/Build/Products/Debug-iphoneos/slsls.app/slsls", arch = "arm64"
Symbol: id = {0x00000048}, range = [0x0000000104d41408-0x0000000104d41430), name="ViewController", mangled="OBJC_CLASS_$_ViewController"
(lldb)
(lldb) p/x $sp
(unsigned long) $4 = 0x000000016b0c9ae0
(lldb) p/x $fp
(unsigned long) $5 = 0x000000016b0c9ba0
通过 lldb
的输出,我们可以得到以下信息:
[NSObject class]
指向了系统共享库 libobjc.A.dylib
映射的内存区域[ViewController class]
地址指向了可执行文件映射的内存区域sp
和 fp
寄存器地址小于 [NSObject class]
的地址综上,我们可以得到结论:iOS 的系统库加载地址在内核与栈区之间。