<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>启动 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E5%90%AF%E5%8A%A8/</link><description>Recent content in 启动 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 08 May 2026 22:56:38 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E5%90%AF%E5%8A%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>启动优化-Initializers</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-initializers/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-initializers/</guid><description>&lt;p&gt;Initializers是指在main函数之前执行的初始化代码，包括C++静态构造函数和&lt;code&gt;__attribute__((constructor))&lt;/code&gt;标记的函数。这些代码会在Pre-main阶段同步执行，阻塞启动。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;以下代码会在main之前执行：&lt;/p&gt;
&lt;h3 id="1-c静态构造函数"&gt;1. C++静态构造函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;__attribute__((constructor))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyInitializer() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 耗时初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; initializeHeavyResource();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-全局静态变量的构造函数"&gt;2. 全局静态变量的构造函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 全局静态变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; globalCache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk(); &lt;span style="color:#75715e"&gt;// 构造函数在main前调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-非基本类型的全局变量"&gt;3. 非基本类型的全局变量&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 非POD类型的全局变量会触发构造函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string globalString &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; MyClass globalObject;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1延迟初始化"&gt;方案1：延迟初始化&lt;/h3&gt;
&lt;p&gt;将全局变量改为懒加载模式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化前：全局变量在main前初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; globalCache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后（纯C++方案，适用于 .cpp 文件）：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mutex&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; getGlobalCache() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;once_flag onceFlag;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;call_once(onceFlag, [&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cache;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后（ObjC++方案，适用于 .mm 文件）：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; getGlobalCache() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; dispatch_once_t onceToken;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_once(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;onceToken, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cache;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="方案2使用swift懒加载"&gt;方案2：使用Swift懒加载&lt;/h3&gt;
&lt;p&gt;Swift的懒加载特性可以避免在启动时初始化：&lt;/p&gt;</description></item><item><title>启动优化-Rebase与Bind</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-rebase%E4%B8%8Ebind/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-rebase%E4%B8%8Ebind/</guid><description>&lt;p&gt;Rebase和Bind是Pre-main阶段的重要步骤，用于修正程序中的指针地址。ObjC类、方法、协议等元数据越多，需要修复的指针越多，启动时间越长。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;p&gt;由于ASLR（Address Space Layout Randomization）技术，App每次启动时加载到内存的地址都是随机的，因此需要进行地址修正。关于Rebase和Bind的底层原理，可以参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/"&gt;Mach-O的链接、装载与库&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="rebase重定位"&gt;Rebase（重定位）&lt;/h3&gt;
&lt;p&gt;修正指向Mach-O内部的指针，将编译时的地址加上ASLR偏移量。&lt;/p&gt;
&lt;h3 id="bind绑定"&gt;Bind（绑定）&lt;/h3&gt;
&lt;p&gt;修正指向Mach-O外部的指针，查找符号表，绑定到正确的外部符号地址。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph compile["编译时 (Mach-O文件)"]
A1["内部指针: 0x1000&lt;br/&gt;(指向内部数据)"]
A2["外部符号: _objc_msgSend&lt;br/&gt;(待绑定)"]
end
subgraph runtime["运行时 (内存中)"]
B1["内部指针: 0x1000 + slide&lt;br/&gt;(Rebase修正)"]
B2["外部符号: 实际地址&lt;br/&gt;(Bind绑定)"]
end
A1 --&gt;|"Rebase"| B1
A2 --&gt;|"Bind"| B2
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;以下因素会增加Rebase/Bind的工作量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;因素&lt;/th&gt;
&lt;th&gt;影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ObjC类数量&lt;/td&gt;
&lt;td&gt;每个类都有元数据需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift类数量&lt;/td&gt;
&lt;td&gt;Swift类在Apple平台也会生成ObjC兼容的元数据，同样需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ObjC方法数量&lt;/td&gt;
&lt;td&gt;方法列表中的指针需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category数量&lt;/td&gt;
&lt;td&gt;Category的方法列表需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++虚函数&lt;/td&gt;
&lt;td&gt;虚函数表中的指针需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;全局变量&lt;/td&gt;
&lt;td&gt;指向其他符号的全局变量需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关于缓存机制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统动态库&lt;/strong&gt;：Rebase/Bind 操作已在 dyld shared cache 中预先完成，不会在 App 启动时执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App 动态库&lt;/strong&gt;：dyld 3 的 Launch Closure 会缓存 Rebase/Bind 的&lt;strong&gt;元数据信息&lt;/strong&gt;（哪些指针需要修正、修正方式等），但 &lt;strong&gt;Rebase/Bind 操作本身仍需每次启动时执行&lt;/strong&gt;，因为 ASLR slide 每次启动都不同&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，减少 ObjC 类、Category、C++ 虚函数等仍然是有效的优化手段。&lt;/p&gt;</description></item><item><title>启动优化-didFinishLaunching</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-didfinishlaunching/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-didfinishlaunching/</guid><description>&lt;p&gt;&lt;code&gt;didFinishLaunchingWithOptions&lt;/code&gt;是main阶段的核心入口，在这里初始化大量SDK和服务会阻塞启动。本文介绍如何优化这个阶段的耗时。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;典型的问题代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 所有初始化都在主线程同步执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CrashReporter.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Analytics.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PushNotification.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NetworkManager.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DatabaseManager.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ImageCache.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AdSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SocialSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 更多SDK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种写法的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;所有初始化都在主线程同步执行&lt;/li&gt;
&lt;li&gt;无论是否需要，所有SDK都在启动时初始化&lt;/li&gt;
&lt;li&gt;阻塞首帧渲染&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1分级启动任务管理"&gt;方案1：分级启动任务管理&lt;/h3&gt;
&lt;p&gt;将启动任务按优先级分类，只在启动时执行必要的任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 启动任务优先级&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LaunchTaskPriority&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;required&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 必须在首帧前完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; high &lt;span style="color:#75715e"&gt;// 首帧后立即执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; normal &lt;span style="color:#75715e"&gt;// 首屏稳定后执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; low &lt;span style="color:#75715e"&gt;// 空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 启动任务管理器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LaunchTaskManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared = LaunchTaskManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tasks: [LaunchTaskPriority: [() -&amp;gt; Void]] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;(priority: LaunchTaskPriority, task: @escaping () -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; tasks[priority] == &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[priority] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[priority]?.append(task)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeRequiredTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[.&lt;span style="color:#66d9ef"&gt;required&lt;/span&gt;]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeHighPriorityTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.high]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeNormalTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.asyncAfter(deadline: .now() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.normal]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeLowPriorityTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 监听RunLoop空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.low]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="使用示例"&gt;使用示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; manager = LaunchTaskManager.shared
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 必须在首帧前完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .&lt;span style="color:#66d9ef"&gt;required&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CrashReporter.setup() &lt;span style="color:#75715e"&gt;// 崩溃收集必须最先初始化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 首帧后立即执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .high) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Analytics.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PushNotification.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 首屏稳定后执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .normal) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AdSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SocialSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .low) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PreloadManager.preloadResources()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 只执行必须的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.executeRequiredTasks()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="任务分级建议"&gt;任务分级建议&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;优先级&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;required&lt;/td&gt;
&lt;td&gt;崩溃收集、核心功能依赖&lt;/td&gt;
&lt;td&gt;Crash SDK、必要的配置加载&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;用户可能很快用到&lt;/td&gt;
&lt;td&gt;推送、统计、网络配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;normal&lt;/td&gt;
&lt;td&gt;非首屏功能&lt;/td&gt;
&lt;td&gt;广告SDK、社交分享&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;预加载、缓存&lt;/td&gt;
&lt;td&gt;图片预加载、数据预热&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="方案2并行初始化"&gt;方案2：并行初始化&lt;/h3&gt;
&lt;p&gt;将无依赖关系的初始化任务并行执行：&lt;/p&gt;</description></item><item><title>启动优化-load方法</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-load%E6%96%B9%E6%B3%95/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-load%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法是ObjC运行时在类被加载时自动调用的方法，所有&lt;code&gt;+load&lt;/code&gt;方法在main函数之前同步执行，会阻塞启动。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法的特点：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main函数之前，ObjC Runtime初始化时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用顺序&lt;/td&gt;
&lt;td&gt;父类 → 子类 → Category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;线程&lt;/td&gt;
&lt;td&gt;主线程，同步执行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;影响&lt;/td&gt;
&lt;td&gt;直接阻塞启动&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：+load中执行耗时操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyModule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 耗时操作会阻塞启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self preloadResources];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self registerServices];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="load与initialize的区别"&gt;+load与+initialize的区别&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;+load&lt;/th&gt;
&lt;th&gt;+initialize&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main之前&lt;/td&gt;
&lt;td&gt;类首次使用时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用次数&lt;/td&gt;
&lt;td&gt;只调用一次&lt;/td&gt;
&lt;td&gt;可能多次（子类触发）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;是否阻塞启动&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用顺序&lt;/td&gt;
&lt;td&gt;父类→子类→Category&lt;/td&gt;
&lt;td&gt;父类→子类&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;更详细的对比请参考：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/"&gt;+load与+initialize的区别&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1使用initialize替代"&gt;方案1：使用+initialize替代&lt;/h3&gt;
&lt;p&gt;将&lt;code&gt;+load&lt;/code&gt;中的逻辑迁移到&lt;code&gt;+initialize&lt;/code&gt;，延迟到类首次使用时执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyModule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initialize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; dispatch_once_t onceToken;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_once(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;onceToken, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 延迟到类首次使用时执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;code&gt;+initialize&lt;/code&gt;可能被子类触发多次调用，需要使用&lt;code&gt;dispatch_once&lt;/code&gt;保证只执行一次。&lt;/p&gt;</description></item><item><title>启动优化-二进制重排</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E4%BA%8C%E8%BF%9B%E5%88%B6%E9%87%8D%E6%8E%92/</link><pubDate>Fri, 08 May 2026 22:56:38 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E4%BA%8C%E8%BF%9B%E5%88%B6%E9%87%8D%E6%8E%92/</guid><description>&lt;p&gt;二进制重排是一种通过重新排列二进制文件中函数顺序来减少启动时Page Fault的优化技术。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本原理"&gt;基本原理&lt;/h2&gt;
&lt;h3 id="page-fault问题"&gt;Page Fault问题&lt;/h3&gt;
&lt;p&gt;iOS使用虚拟内存管理，讨论Page Fault时需要先区分两层“内存”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;虚拟地址空间&lt;/strong&gt;：进程看到的是一段连续的虚拟地址。App启动时，dyld会把Mach-O的&lt;code&gt;__TEXT&lt;/code&gt;、&lt;code&gt;__DATA&lt;/code&gt;等段映射到进程的虚拟地址空间里。这里的“映射”只是建立虚拟地址和文件偏移的关系，不代表整段二进制代码已经全部进入物理内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理内存&lt;/strong&gt;：CPU真正执行代码时，需要对应虚拟页背后有可用的物理页。代码页通常是文件映射页，第一次访问某个尚未驻留在物理内存中的代码页时，会触发Page Fault。内核再从App二进制文件中读取这个页的内容，填充到物理页，并更新页表。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，更准确地说：程序代码按页映射到虚拟地址空间；启动过程中实际执行到某个函数时，才会按需把该函数所在的代码页调入物理内存。Page Fault本身不是异常崩溃，而是虚拟内存按需调页的正常机制，只是冷启动时如果触发太多文件读取，会增加启动耗时。&lt;/p&gt;
&lt;p&gt;默认情况下，编译器按照链接顺序排列函数，导致启动时调用的函数可能分散在不同的代码页中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;优化前（启动函数分散在不同代码页）：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Page 1 │ │ Page 2 │ │ Page 3 │ │ Page 4 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ func_A │ │ func_X │ │ func_B │ │ func_C │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ... │ │ ... │ │ ... │ │ ... │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└────────┘ └────────┘ └────────┘ └────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;启动调用 A→B→C 会触达 Page 1, 3, 4。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;如果这些代码页还没有驻留在物理内存中，就可能产生3次Page Fault。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="二进制重排的效果"&gt;二进制重排的效果&lt;/h3&gt;
&lt;p&gt;通过重排，将启动时调用的函数集中排列在相邻的代码页中：&lt;/p&gt;</description></item><item><title>启动优化-减少动态库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%87%8F%E5%B0%91%E5%8A%A8%E6%80%81%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%87%8F%E5%B0%91%E5%8A%A8%E6%80%81%E5%BA%93/</guid><description>&lt;p&gt;动态库加载是Pre-main阶段的重要组成部分，每个动态库都需要加载、验证签名、进行符号绑定，这些操作会显著影响启动时间。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;当App启动时，dyld需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析Mach-O文件的Load Commands，找出依赖的动态库&lt;/li&gt;
&lt;li&gt;递归加载所有依赖的动态库&lt;/li&gt;
&lt;li&gt;对每个动态库进行签名验证&lt;/li&gt;
&lt;li&gt;执行Rebase和Bind操作&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;动态库数量越多，这些操作的耗时就越长。Apple建议将自定义动态库数量控制在6个以内。关于动态库加载的详细流程，可以参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/"&gt;Mach-O的链接、装载与库&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关于缓存机制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统动态库&lt;/strong&gt;：已被放入 dyld shared cache 中，其加载和符号绑定操作已预先完成，不会影响 App 启动时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App 动态库&lt;/strong&gt;：dyld 3 引入的 Launch Closure 机制会缓存依赖分析、Rebase/Bind 信息等元数据。首次启动（或 App 更新后）会生成缓存，后续启动直接使用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但即使有 Launch Closure 缓存，&lt;strong&gt;Rebase/Bind 操作本身仍需执行&lt;/strong&gt;（因为 ASLR slide 每次启动都不同），动态库数量越多，这些操作的耗时仍然越长。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;App可执行文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── UIKit.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ ├── Foundation.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ │ └── CoreFoundation.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ └── CoreGraphics.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── 自定义Framework A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ └── 依赖库...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── 自定义Framework B
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── 依赖库...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="1-合并动态库"&gt;1. 合并动态库&lt;/h3&gt;
&lt;p&gt;将功能相近的动态库合并为一个：&lt;/p&gt;</description></item><item><title>启动优化-观测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E8%A7%82%E6%B5%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E8%A7%82%E6%B5%8B/</guid><description>&lt;p&gt;准确测量启动时间是优化的前提。启动时间是用户体验的关键指标之一，研究表明，应用性能直接影响用户留存：页面加载时间每增加1秒，用户流失率会显著上升。对于iOS应用，需要在20秒内完成启动，否则可能会被watchdog强制终止。&lt;/p&gt;
&lt;p&gt;本文介绍如何测量和监控iOS应用的启动时间。关于启动流程的详细介绍，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/"&gt;App启动流程&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一测量方式概览"&gt;一、测量方式概览&lt;/h2&gt;
&lt;p&gt;iOS 提供了多种测量启动时间的方式，适用于不同场景：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;th&gt;粒度&lt;/th&gt;
&lt;th&gt;是否需要代码&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dyld 环境变量&lt;/td&gt;
&lt;td&gt;开发调试&lt;/td&gt;
&lt;td&gt;定性分析&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruments App Launch&lt;/td&gt;
&lt;td&gt;深度分析&lt;/td&gt;
&lt;td&gt;函数级&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;代码埋点&lt;/td&gt;
&lt;td&gt;开发调试 + 线上监控&lt;/td&gt;
&lt;td&gt;自定义&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MetricKit&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;td&gt;冷启动/热启动&lt;/td&gt;
&lt;td&gt;少量代码&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二开发调试阶段"&gt;二、开发调试阶段&lt;/h2&gt;
&lt;h3 id="21-dyld-环境变量"&gt;2.1 dyld 环境变量&lt;/h3&gt;
&lt;p&gt;通过设置 dyld 环境变量可以在控制台查看启动过程中的加载信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Edit Scheme → Run → Arguments → Environment Variables
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与启动测量相关的环境变量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;环境变量&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;th&gt;启动分析用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_LIBRARIES&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每个加载的 mach-o 镜像&lt;/td&gt;
&lt;td&gt;查看动态库加载顺序，确认是否加载了不必要的库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_LOADERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印镜像的加载器类型（JustInTimeLoader / PrebuiltLoader）&lt;/td&gt;
&lt;td&gt;分析是否使用了启动闭包优化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_INITIALIZERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每个 initializer 的执行&lt;/td&gt;
&lt;td&gt;查看 +load、constructor、C++ 静态构造函数的执行顺序&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_BINDINGS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每次符号绑定&lt;/td&gt;
&lt;td&gt;分析符号绑定情况（输出量很大）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_SEARCHING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印库搜索路径&lt;/td&gt;
&lt;td&gt;排查库加载问题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_APIS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印 dyld API 调用（如 dlopen）&lt;/td&gt;
&lt;td&gt;检测运行时动态加载行为&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_TO_FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;将日志输出到指定文件&lt;/td&gt;
&lt;td&gt;避免控制台日志过多，方便后续分析&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;使用示例&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>启动优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;iOS应用的启动时间是用户体验的关键指标之一。研究表明，应用性能直接影响用户留存：页面加载时间每增加1秒，用户流失率会显著上升。对于iOS应用，需要在20秒内完成启动，否则可能会被watchdog强制终止。&lt;/p&gt;
&lt;p&gt;本系列文章从启动流程的各个阶段入手，系统性地介绍iOS启动优化的方法和实践。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;启动监控是 APM 的重要子系，线上 P50/P90/P99 的采集、冷/温/热启动判定、以及与业务秒开指标的关联，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM 系列&lt;/a&gt;：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/"&gt;指标体系&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;数据采集&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="启动流程概述"&gt;启动流程概述&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/"&gt;App的启动流程&lt;/a&gt;分为两个主要阶段：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;时间范围&lt;/th&gt;
&lt;th&gt;主要工作&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-main&lt;/td&gt;
&lt;td&gt;进程创建 → main()函数&lt;/td&gt;
&lt;td&gt;加载可执行文件、加载动态库、Rebase/Bind、ObjC Runtime初始化、Swift Runtime元数据注册、+load方法、Initializers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;main&lt;/td&gt;
&lt;td&gt;main()函数 → 首帧渲染&lt;/td&gt;
&lt;td&gt;UIApplicationMain、AppDelegate回调、首帧渲染&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class="mermaid"&gt;flowchart TD
Start([App 冷启动]) --&gt; PreMain
subgraph PreMain["Pre-main 阶段"]
direction TB
A[加载可执行文件&lt;br/&gt;创建进程、mmap映射、签名验证] --&gt; B[加载动态库&lt;br/&gt;递归加载依赖、包括 Swift Runtime]
B --&gt; C[Rebase &amp; Bind&lt;br/&gt;指针修正、符号绑定]
C --&gt; D[ObjC Runtime 初始化&lt;br/&gt;类注册、Category 附加]
D --&gt; E[Swift Runtime 元数据注册&lt;br/&gt;类型元数据、协议遵循表]
E --&gt; F[调用 +load 方法]
F --&gt; G[执行 Initializers&lt;br/&gt;C++静态构造函数、__attribute__]
end
PreMain --&gt; MainPhase
subgraph MainPhase["main 阶段"]
direction TB
H[main函数] --&gt; I[UIApplicationMain&lt;br/&gt;创建UIApplication、AppDelegate、启动RunLoop]
I --&gt; J[AppDelegate回调&lt;br/&gt;willFinish、didFinishLaunching]
J --&gt; K[首帧渲染&lt;br/&gt;创建Window、RootViewController、首屏UI]
end
MainPhase --&gt; End([启动完成])
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item></channel></rss>