iOS 15 如何让 App 启动更快?
部署在 macOS 12 或 iOS 15 及更高版本操作系统上的所有程序及 dylibs现在都使用链式修复格式。这种格式使用不同的加载命令和 LINKEDIT 数据,不能在低版本的操作系统上运行或加载。
% xcrun dyldinfo -rebase -bind Snapchat.app/Snapchat
rebase information (from compressed dyld info):
segment section address type
__DATA __got 0x10748C0C8 pointer
...
bind information:
segment section address type addend dylib symbol
__DATA __const 0x107595A70 pointer 0 libswiftCore
_$sSHMp
一种新的格式
% otool -l iOS14Example.app/iOS14Example | grep LC_DYLD
cmd LC_DYLD_INFO_ONLY% otool -l iOS15Example.app/iOS15Example | grep LC_DYLD
cmd LC_DYLD_CHAINED_FIXUPS
cmd LC_DYLD_EXPORTS_TRIE
let bytes = (try! Data(contentsOf: url) as NSData).bytes
bytes.processLoadComands { load_command, pointer in
if load_command.cmd == LC_DYLD_EXPORTS_TRIE {
let dataCommand = pointer.load(as: linkedit_data_command.self)
bytes.advanced(by: Int(dataCommand.dataoff)).readExportTrie()
}
}
extension UnsafeRawPointer {
func readExportTrie() {
var frontier = readNode(name: "")
guard !frontier.isEmpty else { return }
repeat {
let (prefix, offset) = frontier.removeFirst()
let children = advanced(by: Int(offset)).readNode(name: prefix)
for (suffix, offset) in children {
frontier.append((prefix + suffix, offset))
}
} while !frontier.isEmpty
}
// Returns an array of child nodes and their offset
func readNode(name: String) -> [(String, UInt)] {
guard load(as: UInt8.self) == 0 else {
// This is a terminal node
print("symbol name \(name)")
return []
}
let numberOfBranches = UInt(advanced(by: 1).load(as: UInt8.self))
var mutablePointer = self.advanced(by: 2)
var result = [(String, UInt)]()
for _ in 0..<numberOfBranches {
result.append(
(mutablePointer.readNullTerminatedString(),
mutablePointer.readULEB()))
}
return result
}
}
链
struct dyld_chained_ptr_64_rebase
{
uint64_t target : 36,
high8 : 8,
reserved : 7, // 0s
next : 12,
bind : 1; // Always 0 for a rebase
};
% xcrun dyldinfo -rebase Snapchat.app/Snapchat > rebases
% ruby -e 'puts IO.read("rebases").split("\n").drop(2).map { |a| a.split(" ")[2].to_i(16) / 16384 }.uniq.count'
1554% xcrun dyldinfo -bind Snapchat.app/Snapchat > binds
450
减少动态框架的数量
减少应用程序大小,从而减少内存页面的使用(这就是我制作 Emerge 的原因!)
将代码移出 +加载以及静态初始化程序
使用 更少的类
将工作推迟到绘制第一个框架后
参考链接:
[1] The symbol from dyldinfo is mangled, you can get the human readable name with xcrun swift-demangle '_$sSHMp'. [2] Exports are the second piece of a bind. One binary binds to symbols exported from its dependencies. [3] The same goes for binds, a pointer is actually a union of rebase and bind (dyld_chained_ptr_64_bind) with a single bit used to differentiate the two. Binds also require the imported symbol name which isn’t discussed here. [4] https://asciiwwdc.com/2016/sessions/406
iOS 15 内置原生壁纸下载 优酷 iOS 插件化页面架构方法 这也行?iOS后台锁屏监听摇一摇 189.31G iOS 学习资料分享 iOS APP图标版本化
评论