<?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/categories/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/</link><description>Recent content in 性能优化 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 21 Jun 2026 22:41:52 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/categories/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/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><item><title>耗电-CPU与后台优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-cpu%E4%B8%8E%E5%90%8E%E5%8F%B0%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/power-cpu%E4%B8%8E%E5%90%8E%E5%8F%B0%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;CPU是App最容易&amp;quot;无意识&amp;quot;耗电的模块，而后台则是最容易&amp;quot;偷偷&amp;quot;耗电的场景。本文聚焦这两大问题域，给出具体的优化手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一cpu耗电的根本原因"&gt;一、CPU耗电的根本原因&lt;/h2&gt;
&lt;p&gt;根据 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/"&gt;耗电-原理&lt;/a&gt; 中的分析，CPU耗电由三部分构成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;活跃时间&lt;/strong&gt;：CPU处于C0/P0的时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;瞬时功率&lt;/strong&gt;：和P-State频率相关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;唤醒次数&lt;/strong&gt;：频繁从C-State唤醒无法进入深度休眠。&lt;/li&gt;
&lt;/ol&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&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;避免无谓的满核满频，使用合适的QoS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;合并唤醒&lt;/td&gt;
&lt;td&gt;聚合Timer、聚合任务，让CPU能连续工作后进入深休眠&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二识别cpu耗电热点"&gt;二、识别CPU耗电热点&lt;/h2&gt;
&lt;h3 id="从metrickit入手"&gt;从MetricKit入手&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cumulativeCPUTime&lt;/code&gt; 是线上最直接的CPU指标。对比同版本前后、同机型前后的CPU时长，能快速定位回归。&lt;/p&gt;
&lt;h3 id="time-profiler的使用技巧"&gt;Time Profiler的使用技巧&lt;/h3&gt;
&lt;p&gt;在Instruments中抓一份Time Profiler Trace后：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按&amp;quot;Heavy Stack&amp;quot;视图查看耗时函数。&lt;/li&gt;
&lt;li&gt;关注&lt;strong&gt;后台&lt;/strong&gt;的采样（通过Xcode的生命周期切换复现）。&lt;/li&gt;
&lt;li&gt;查看&lt;strong&gt;线程调用频率&lt;/strong&gt;——单次耗时低但高频调用的函数，同样是耗电大头。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="代码层面的cpu异味"&gt;代码层面的CPU异味&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:#75715e"&gt;// 1. 死循环轮询&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; isWaitingForData {
&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; dataReady { &lt;span style="color:#66d9ef"&gt;break&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;// 2. 主线程sleep循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DispatchQueue.global().async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&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; checkStatus()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Thread.sleep(forTimeInterval: &lt;span style="color:#ae81ff"&gt;0.1&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. 密集Timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Timer.scheduledTimer(withTimeInterval: &lt;span style="color:#ae81ff"&gt;0.016&lt;/span&gt;, repeats: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) { &lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&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;.updateUI()
&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;// 4. 无限制的CADisplayLink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;displayLink = CADisplayLink(target: &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;, selector: &lt;span style="color:#66d9ef"&gt;#selector&lt;/span&gt;(tick))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;displayLink.add(to: .main, forMode: .common)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 页面隐藏后忘记invalidate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些代码在Time Profiler中都会显示出异常高的调用频率。&lt;/p&gt;</description></item><item><title>耗电-原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;本文从硬件功耗模型、iOS系统的能效调度机制、以及各个硬件模块的功耗特性三个维度，系统性地讲解iOS App耗电的底层原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="功耗的基本概念"&gt;功耗的基本概念&lt;/h2&gt;
&lt;h3 id="功率能量与电量"&gt;功率、能量与电量&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功率（Power）&lt;/strong&gt;：单位时间内消耗的能量，单位为瓦特（W）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能量（Energy）&lt;/strong&gt;：功率在时间上的积分，单位为焦耳（J）或毫瓦时（mWh）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;电量（Battery Capacity）&lt;/strong&gt;：电池能存储的总能量，单位为毫安时（mAh）。&lt;/li&gt;
&lt;/ul&gt;
\[ Energy = \int P(t)\,dt \]&lt;p&gt;对于一段时间内近似恒定的功率，可以简化为 \( E = P \times t \)。这也是所有耗电优化的起点——要么降功率（P），要么降时间（t）。&lt;/p&gt;
&lt;h3 id="电池电压与电流"&gt;电池电压与电流&lt;/h3&gt;
&lt;p&gt;iPhone使用锂电池，标称电压约为3.7~3.8V。操作系统看到的电流则随着硬件负载实时变化。可以近似认为：&lt;/p&gt;
\[ P(t) = V \times I(t) \]&lt;p&gt;在App层面，我们无法直接测量V和I，但可以通过 &lt;code&gt;UIDevice.current.batteryLevel&lt;/code&gt; 观察电量百分比，通过 &lt;code&gt;IOKit&lt;/code&gt; 私有API读取更精细的电池状态（后面检测篇会详细讲）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="硬件功耗特性"&gt;硬件功耗特性&lt;/h2&gt;
&lt;p&gt;不同硬件模块的功耗曲线差异非常大。理解每个模块的特性，才能找到最有效的优化点。&lt;/p&gt;
&lt;h3 id="cpup-state与c-state"&gt;CPU：P-State与C-State&lt;/h3&gt;
&lt;p&gt;现代CPU（包括Apple Silicon）通过 &lt;strong&gt;动态电压频率调整（DVFS）&lt;/strong&gt; 来平衡性能与功耗。&lt;/p&gt;
&lt;h4 id="p-stateperformance-state"&gt;P-State（Performance State）&lt;/h4&gt;
&lt;p&gt;P-State描述CPU在工作时的电压/频率档位。以Apple A系列芯片为例，大核和小核都有多个P-State：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph P-State
P0["P0&lt;br/&gt;最高频率&lt;br/&gt;功耗最大"]
P1["P1&lt;br/&gt;中高频率"]
P2["P2&lt;br/&gt;中低频率"]
P3["P3&lt;br/&gt;低频率&lt;br/&gt;功耗小"]
end
P0 -.-&gt;|负载下降| P1
P1 -.-&gt; P2
P2 -.-&gt; P3
P3 -.-&gt;|负载上升| P0
&lt;/pre&gt;
&lt;p&gt;CPU的功耗与频率大致呈 &lt;strong&gt;立方关系&lt;/strong&gt;（电压随频率升高，功耗 ≈ V² × f ≈ f³）。这意味着：&lt;/p&gt;</description></item><item><title>耗电-定位与传感器优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%AE%9A%E4%BD%8D%E4%B8%8E%E4%BC%A0%E6%84%9F%E5%99%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/power-%E5%AE%9A%E4%BD%8D%E4%B8%8E%E4%BC%A0%E6%84%9F%E5%99%A8%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;定位是iOS设备上公认的&amp;quot;耗电大户&amp;quot;，GPS冷启动一次动辄十几秒的高功耗；传感器（加速度计、陀螺仪等）虽然单次功耗不高，但高频采样会累积成可观的电量消耗；屏幕则是 &lt;strong&gt;持续&lt;/strong&gt; 耗电的模块，其功耗和亮度、刷新率、像素颜色都强相关。本文聚焦这三类问题，给出工程化的优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一定位精度与功耗的关系"&gt;一、定位精度与功耗的关系&lt;/h2&gt;
&lt;p&gt;iOS通过 &lt;code&gt;CLLocationManager&lt;/code&gt; 提供定位服务，底层融合了 &lt;strong&gt;GPS、蜂窝基站、WiFi、蓝牙信标&lt;/strong&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;th&gt;典型功耗&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyBestForNavigation&lt;/td&gt;
&lt;td&gt;&amp;lt;5m&lt;/td&gt;
&lt;td&gt;GPS + 传感器融合（需插电）&lt;/td&gt;
&lt;td&gt;极高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyBest&lt;/td&gt;
&lt;td&gt;~10m&lt;/td&gt;
&lt;td&gt;GPS持续&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyNearestTenMeters&lt;/td&gt;
&lt;td&gt;~10m&lt;/td&gt;
&lt;td&gt;GPS + WiFi&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyHundredMeters&lt;/td&gt;
&lt;td&gt;~100m&lt;/td&gt;
&lt;td&gt;WiFi + 基站&lt;/td&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyKilometer&lt;/td&gt;
&lt;td&gt;~1km&lt;/td&gt;
&lt;td&gt;WiFi + 基站（低频）&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyThreeKilometers&lt;/td&gt;
&lt;td&gt;~3km&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;blockquote&gt;
&lt;p&gt;注：iOS 14+ 引入的 &lt;strong&gt;ReducedAccuracy&lt;/strong&gt; 是用户授权层面的&amp;quot;粗略位置&amp;quot;，通过 &lt;code&gt;CLAccuracyAuthorization.reducedAccuracy&lt;/code&gt; 体现，而不是 &lt;code&gt;desiredAccuracy&lt;/code&gt; 常量。即使 App 申请了高精度，只要用户选择了&amp;quot;粗略位置&amp;quot;，系统就只会返回约5公里精度的数据，功耗也随之降到极低。&lt;/p&gt;
&lt;/blockquote&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;导航&lt;/td&gt;
&lt;td&gt;BestForNavigation（仅使用中 + 插电时）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;打车、骑行记录&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;外卖、附近的人&lt;/td&gt;
&lt;td&gt;HundredMeters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;天气、资讯推荐&lt;/td&gt;
&lt;td&gt;Kilometer 或 ThreeKilometers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;反欺诈、粗粒度风控&lt;/td&gt;
&lt;td&gt;ReducedAccuracy（尊重隐私 + 省电）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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:#75715e"&gt;// Bad: 所有场景都用Best，页面打开就开，关闭不关&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.desiredAccuracy = kCLLocationAccuracyBest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.startUpdatingLocation()
&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;// Bad: distanceFilter用kCLDistanceFilterNone，每次都回调&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.distanceFilter = kCLDistanceFilterNone
&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WeatherLocationClient&lt;/span&gt;: NSObject, CLLocationManagerDelegate {
&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;let&lt;/span&gt; manager = CLLocationManager()
&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; completion: ((CLLocation) -&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.delegate = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.desiredAccuracy = kCLLocationAccuracyKilometer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.distanceFilter = &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 500米才更新&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;requestOnce&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; completion: @escaping (CLLocation) -&amp;gt; Void) {
&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;.completion = completion
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.requestLocation() &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:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;locationManager&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; manager: CLLocationManager, didUpdateLocations locs: [CLLocation]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; loc = locs.last &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion?(loc)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion = &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; }
&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;locationManager&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; manager: CLLocationManager, didFailWithError error: Error) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion = &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; }
&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;code&gt;requestLocation()&lt;/code&gt;（iOS 9+）是最省电的一次性定位入口，系统会在获取到满足精度的定位后自动停止硬件。&lt;/p&gt;</description></item><item><title>耗电-检测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%A3%80%E6%B5%8B/</link><pubDate>Fri, 08 May 2026 22:35:33 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%A3%80%E6%B5%8B/</guid><description>&lt;p&gt;本文介绍iOS耗电问题的检测手段，从开发阶段的本地工具，到线上的监控体系，帮助团队形成一套完整的耗电可观测能力。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="检测手段全景"&gt;检测手段全景&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph Dev["研发阶段"]
EG["Xcode Energy Gauge&lt;br/&gt;实时能效评分"]
Inst["Instruments&lt;br/&gt;Energy Log / Time Profiler"]
XCT["XCTest能效测试"]
end
subgraph Test["测试阶段"]
Thermal["热节流测试"]
Battery["真机电量消耗测试"]
IOKit["IOKit内部分析"]
LPM["低电量模式回归"]
end
subgraph Online["线上阶段"]
MK["MetricKit"]
Self["自建实时采集&lt;br/&gt;电量 / CPU / Thermal / 生命周期"]
Report["埋点上报&lt;br/&gt;数据看板"]
end
Dev --&gt; Test --&gt; Online
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="一xcode-energy-gauge"&gt;一、Xcode Energy Gauge&lt;/h2&gt;
&lt;p&gt;Xcode在真机调试时，&amp;ldquo;Debug Navigator → Energy Impact&amp;quot;提供了实时能效评估。&lt;/p&gt;
&lt;h3 id="能效评分energy-impact"&gt;能效评分（Energy Impact）&lt;/h3&gt;
&lt;p&gt;Xcode将功耗分为5档：&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;Very Low / Low&lt;/td&gt;
&lt;td&gt;正常使用&lt;/td&gt;
&lt;td&gt;0&lt;del&gt;3 / 4&lt;/del&gt;8&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;9~16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;严重，必须优化&lt;/td&gt;
&lt;td&gt;17~20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;评分由以下几个因素构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;：平均CPU使用率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network&lt;/strong&gt;：网络活跃时间与流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Location&lt;/strong&gt;：定位活跃时间与精度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU&lt;/strong&gt;：GPU活跃时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background&lt;/strong&gt;：后台活跃时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overhead&lt;/strong&gt;：系统唤醒代价。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="典型使用流程"&gt;典型使用流程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Xcode连接真机（模拟器的数据不准确）。&lt;/li&gt;
&lt;li&gt;运行App，选择Debug Navigator → Energy Impact。&lt;/li&gt;
&lt;li&gt;进行典型操作（刷Feed、看视频、聊天等），观察评分。&lt;/li&gt;
&lt;li&gt;如果出现High/Very High，使用Instruments进一步定位。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="二instruments-energy-log"&gt;二、Instruments Energy Log&lt;/h2&gt;
&lt;p&gt;Instruments中有多个和能效相关的工具：&lt;/p&gt;</description></item><item><title>耗电-治理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%B2%BB%E7%90%86/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%B2%BB%E7%90%86/</guid><description>&lt;p&gt;前面几篇分别讲了耗电的原理、检测、以及CPU/网络/定位/屏幕的具体优化手段。本文把这些内容整合起来，给出一套面向工程团队的 &lt;strong&gt;耗电治理体系&lt;/strong&gt;：从研发规范、线上监控、问题排查到常态化运营。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;耗电治理是 APM 资源子系的一部分，与稳定性、流畅性、启动指标共用同一套监控与告警基础设施。完整的 APM 建设方案见 &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%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;数据采集&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/b%E7%AB%AF%E5%B9%B3%E5%8F%B0%E8%AE%BE%E8%AE%A1/"&gt;B端平台设计&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一治理体系全景"&gt;一、治理体系全景&lt;/h2&gt;
&lt;p&gt;一个成熟的iOS耗电治理体系通常由四个闭环组成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph Dev["研发侧"]
R1["能效规范"]
R2["架构层能效约束"]
R3["Code Review清单"]
end
subgraph Test["测试侧"]
T1["XCTest能效基线"]
T2["真机续航测试"]
T3["极端场景矩阵"]
end
subgraph Online["线上侧"]
O1["MetricKit接入"]
O2["自建CPU/电量采样"]
O3["场景化埋点"]
O4["大盘 + 告警"]
end
subgraph Gov["运营侧"]
G1["版本耗电报告"]
G2["Top问题跟进"]
G3["复盘与规范迭代"]
end
Dev --&gt; Test --&gt; Online --&gt; Gov --&gt; Dev
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="二研发阶段的能效规范"&gt;二、研发阶段的能效规范&lt;/h2&gt;
&lt;h3 id="模块准入清单"&gt;模块准入清单&lt;/h3&gt;
&lt;p&gt;每个新增模块在接入主App前，必须回答以下问题：&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;CPU&lt;/td&gt;
&lt;td&gt;是否有常驻Timer？是否有轮询？是否在不可见时暂停？&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;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;是否申请Background Mode？如何收敛？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动画/渲染&lt;/td&gt;
&lt;td&gt;是否有长驻动画？是否适配ProMotion？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low Power&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;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/power-%E7%BD%91%E7%BB%9C%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/power-%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;网络是iOS设备上仅次于屏幕的耗电大户。和其他模块不同，网络耗电的&amp;quot;坑&amp;quot;非常隐蔽——请求本身只持续几十毫秒，但无线电（Radio）会有10~20秒的&amp;quot;尾能耗&amp;quot;。本文从无线电能效模型出发，给出具体的网络优化手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一无线电能效模型回顾"&gt;一、无线电能效模型回顾&lt;/h2&gt;
&lt;h3 id="rrc状态机再看一眼"&gt;RRC状态机再看一眼&lt;/h3&gt;
&lt;p&gt;无线电不是&amp;quot;开就费电、关就不费电&amp;quot;这么简单。它在连接和空闲之间存在中间状态：&lt;/p&gt;
&lt;pre class="mermaid"&gt;stateDiagram-v2
[*] --&gt; Idle: 初始/长时间空闲
Idle --&gt; Connected: 发送/接收
Connected --&gt; ShortDRX: 空闲~1秒
ShortDRX --&gt; LongDRX: 空闲~5秒
LongDRX --&gt; Idle: 空闲~10秒
Connected --&gt; Connected: 持续通信
ShortDRX --&gt; Connected: 新请求
LongDRX --&gt; Connected: 新请求
&lt;/pre&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;Connected&lt;/td&gt;
&lt;td&gt;最高（&lt;del&gt;1&lt;/del&gt;2W）&lt;/td&gt;
&lt;td&gt;数据传输中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short DRX&lt;/td&gt;
&lt;td&gt;中等&lt;/td&gt;
&lt;td&gt;周期性监听页 paging，仍持有连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long DRX&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;td&gt;周期变长，仍在空中接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle&lt;/td&gt;
&lt;td&gt;极低（~几mW）&lt;/td&gt;
&lt;td&gt;完全释放&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一次请求从发起到彻底回到Idle大约 &lt;strong&gt;12~20秒&lt;/strong&gt;。这个尾巴就是&amp;quot;Tail Energy&amp;quot;。&lt;/p&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10次请求，每次间隔2秒：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Radio持续处于Connected/DRX状态 ≈ 30秒
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- 实际传输时间可能只有几百ms
&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;10次请求合并成1次:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Radio活跃时间 ≈ 15秒（主要是尾巴）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- 节省约50%~70%的Radio能耗
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;结论：网络能效的核心就是&amp;quot;减少Radio醒来的次数&amp;quot;。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>耗电</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E8%80%97%E7%94%B5/</link><pubDate>Fri, 08 May 2026 22:35:33 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E8%80%97%E7%94%B5/</guid><description>&lt;p&gt;耗电（Energy Consumption）是移动应用质量的重要指标之一。一款耗电过快的App会直接影响用户的续航体验，轻则被用户吐槽，重则被系统标记为&amp;quot;耗电大户&amp;quot;（在iOS的&amp;quot;设置 → 电池&amp;quot;中显示），最终被用户卸载。&lt;/p&gt;
&lt;p&gt;本系列文章从iOS功耗模型入手，系统性地介绍耗电问题的原理、检测、优化与治理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="为什么要关注耗电"&gt;为什么要关注耗电&lt;/h2&gt;
&lt;p&gt;iOS设备的电池容量有限（iPhone通常在3000~5000mAh），而应用的功耗会直接影响续航时间。苹果在iOS 8之后提供了&amp;quot;电池用量&amp;quot;统计入口，用户可以清楚地看到每个App消耗的电量比例。&lt;/p&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;后台待机一晚电量掉20%&lt;/td&gt;
&lt;td&gt;手机放着不用也掉电&lt;/td&gt;
&lt;td&gt;后台定位、后台音频、后台Fetch未合理释放&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App使用1小时电量掉30%&lt;/td&gt;
&lt;td&gt;使用过程电量下降过快&lt;/td&gt;
&lt;td&gt;CPU长时间高占用、高频网络请求、GPU密集渲染&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;手机发烫&lt;/td&gt;
&lt;td&gt;设备温度异常升高&lt;/td&gt;
&lt;td&gt;CPU/GPU长期满载、持续定位、频繁屏幕唤醒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;被系统标记为&amp;quot;后台活动&amp;quot;过高&lt;/td&gt;
&lt;td&gt;系统提示&amp;quot;此App正在消耗大量电池&amp;quot;&lt;/td&gt;
&lt;td&gt;后台任务未合理调度，违反能效规则&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;苹果对&amp;quot;耗电&amp;quot;非常敏感——从iOS 9开始引入低电量模式（Low Power Mode），从iOS 13开始加强后台任务的能效审查（BackgroundTasks框架），从iOS 15开始通过MetricKit将功耗数据开放给开发者。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="ios功耗模型概述"&gt;iOS功耗模型概述&lt;/h2&gt;
&lt;p&gt;iOS设备的功耗来源可以分为以下几大类：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
Battery["电池总功耗"]
Battery --&gt; CPU["CPU&lt;br/&gt;计算、编解码"]
Battery --&gt; GPU["GPU&lt;br/&gt;渲染、图层合成"]
Battery --&gt; Screen["屏幕&lt;br/&gt;显示、亮度、刷新率"]
Battery --&gt; Network["网络&lt;br/&gt;蜂窝、WiFi、BLE"]
Battery --&gt; Location["定位&lt;br/&gt;GPS、基站、WiFi定位"]
Battery --&gt; Sensor["传感器&lt;br/&gt;加速度计、陀螺仪、气压计"]
Battery --&gt; Audio["音视频&lt;br/&gt;录制、播放、相机"]
Battery --&gt; Storage["存储&lt;br/&gt;磁盘IO"]
Battery --&gt; IO["外设&lt;br/&gt;蓝牙、NFC、UWB"]
&lt;/pre&gt;
&lt;p&gt;不同硬件模块的功耗量级差异很大。参考苹果WWDC的数据，定位和蜂窝数据通常是&amp;quot;耗电大户&amp;quot;，屏幕是&amp;quot;持续耗电大户&amp;quot;，而CPU/GPU在计算密集时瞬时功耗最高。&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;/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;GPS定位&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;冷启动搜星耗电特别明显&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU/GPU&lt;/td&gt;
&lt;td&gt;中~高&lt;/td&gt;
&lt;td&gt;计算量决定功耗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WiFi&lt;/td&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;td&gt;比蜂窝省电&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝牙（BLE）&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;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="耗电问题的本质"&gt;耗电问题的本质&lt;/h2&gt;
&lt;p&gt;耗电问题的本质可以用一个简单的公式表示：&lt;/p&gt;</description></item><item><title>JetsamEvent 日志解读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</guid><description>&lt;p&gt;JetsamEvent 是 iOS 唯一由系统官方生成、且专门记录&amp;quot;因内存原因终止进程&amp;quot;的日志。它不记录线程堆栈，却完整刻画了&lt;strong&gt;发生强杀那一刻&lt;/strong&gt;整机的内存分布——这使它成为 OOM 归因、阈值建模、后台生命周期治理最权威的数据源。&lt;/p&gt;
&lt;p&gt;本文聚焦 JetsamEvent 日志本身：存放位置、文件结构、字段含义、&lt;code&gt;reason&lt;/code&gt; 类型、案例解读、自动化批量解析脚本，以及机型内存上限/iOS 版本差异等实战要点。OOM 监控治理的整体方法论见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/#8-oomout-of-memory%E5%B4%A9%E6%BA%83"&gt;崩溃-治理&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-jetsam-与-jetsamevent-是什么"&gt;1. Jetsam 与 JetsamEvent 是什么&lt;/h2&gt;
&lt;p&gt;iOS 通过 XNU 内核的 &lt;code&gt;memorystatus&lt;/code&gt; 子系统（俗称 Jetsam）做整机内存管理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前台/后台进程按 Jetsam 优先级排序；&lt;/li&gt;
&lt;li&gt;当系统整体可用物理页（&lt;code&gt;vm_page_free_count&lt;/code&gt;）或单个进程 &lt;code&gt;phys_footprint&lt;/code&gt; 触发阈值时，按优先级杀掉进程；&lt;/li&gt;
&lt;li&gt;被杀时，内核在 &lt;code&gt;/var/mobile/Library/Logs/CrashReporter/&lt;/code&gt; 生成 &lt;code&gt;JetsamEvent-yyyy-MM-dd-HHmmss.ips&lt;/code&gt; 文件，并通过 &lt;code&gt;DiagnosticsReporting&lt;/code&gt; 暴露给 &lt;em&gt;设置 → 隐私与安全性 → 分析与改进 → 分析数据&lt;/em&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要理解两个关键结论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;JetsamEvent 不是单个进程的崩溃日志，而是整机一次 Jetsam 事件的快照。&lt;/strong&gt; 一个文件里往往包含几十个进程条目，只有其中一个（或少数）被真正杀掉；其余进程是作为&amp;quot;当时整机内存画像&amp;quot;被附带记录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JetsamEvent 不含线程堆栈。&lt;/strong&gt; 它的价值在于告诉你&amp;quot;谁占用了多少内存&amp;quot;和&amp;quot;为什么被杀&amp;quot;，而不是&amp;quot;在哪一行代码被杀&amp;quot;。堆栈需要由 App 自己的 Memory Dump / MetricKit 补齐。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-获取方式"&gt;2. 获取方式&lt;/h2&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;设置 → 隐私与安全性 → 分析与改进 → 分析数据，文件名 &lt;code&gt;JetsamEvent-*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode 连接真机&lt;/td&gt;
&lt;td&gt;Window → Devices and Simulators → 选中设备 → View Device Logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sysdiagnose 包&lt;/td&gt;
&lt;td&gt;解压后位于 &lt;code&gt;crashes_and_spins/*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;越狱设备&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/var/mobile/Library/Logs/CrashReporter/JetsamEvent-*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自动上报&lt;/td&gt;
&lt;td&gt;App 下次启动时扫描沙盒外的 Apple 日志目录不可行，只能依赖 &lt;code&gt;MetricKit&lt;/code&gt; 的 &lt;code&gt;MXCrashDiagnostic&lt;/code&gt;/&lt;code&gt;MXAppExitMetric&lt;/code&gt;（iOS 14+）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ iOS 沙盒下 App 无法直接读取 &lt;code&gt;/var/mobile/Library/Logs/&lt;/code&gt; 的原始 ips 文件，线上规模化采集必须走 MetricKit。JetsamEvent 原始日志主要用于研发期抓真机、或用户反馈场景的手工分析。&lt;/p&gt;</description></item><item><title>崩溃-Mach异常</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-mach%E5%BC%82%E5%B8%B8/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-mach%E5%BC%82%E5%B8%B8/</guid><description>&lt;p&gt;本文深入介绍Mach异常的底层实现细节，包括端口操作、消息机制以及如何实现自定义的Mach异常处理器。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于Mach异常的基础概念（Task、Thread、Port、Message）和异常端口的查找顺序，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/"&gt;崩溃-原理&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="mach端口详解"&gt;Mach端口详解&lt;/h2&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-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;┌─────────────────────────────────────────────────────────────┐
&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;│ MACH_PORT_RIGHT_SEND │
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_RECEIVE │
&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&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;│ MACH_PORT_RIGHT_SEND_ONCE │
&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;│ MACH_PORT_RIGHT_PORT_SET │
&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;│ MACH_PORT_RIGHT_DEAD_NAME │
&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&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-c" data-lang="c"&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;mach/mach.h&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&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;mach_port_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&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; MACH_PORT_RIGHT_RECEIVE, &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:#f92672"&gt;&amp;amp;&lt;/span&gt;port &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;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND &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;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_destroy&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(), port);
&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;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_deallocate&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(), port);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="mach消息"&gt;Mach消息&lt;/h2&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-c" data-lang="c"&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;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_bits_t&lt;/span&gt; msgh_bits; &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;mach_msg_size_t&lt;/span&gt; msgh_size; &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;mach_port_t&lt;/span&gt; msgh_remote_port; &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;mach_port_t&lt;/span&gt; msgh_local_port; &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;mach_port_name_t&lt;/span&gt; msgh_voucher_port;&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;mach_msg_id_t&lt;/span&gt; msgh_id; &lt;span style="color:#75715e"&gt;// 消息ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&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;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&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;mach_msg_body_t&lt;/span&gt; body;
&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;mach_msg_port_descriptor_t&lt;/span&gt; port;
&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;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} MyMessage;
&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-c" data-lang="c"&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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_message&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; port, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;data, &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } message;
&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; message.header.msgh_bits &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MACH_MSGH_BITS&lt;/span&gt;(MACH_MSG_TYPE_COPY_SEND, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MACH_PORT_NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;size_t&lt;/span&gt; copy_len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message.data) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; len : &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message.data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;(message.data, data, copy_len);
&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:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;message.header,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_SEND_MSG, &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;sizeof&lt;/span&gt;(message), &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:#ae81ff"&gt;0&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; MACH_PORT_NULL, &lt;span style="color:#75715e"&gt;// 接收端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE, &lt;span style="color:#75715e"&gt;// 超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL &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&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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;receive_message&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; port) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } message;
&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;kern_return_t&lt;/span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;message.header,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG, &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:#ae81ff"&gt;0&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;sizeof&lt;/span&gt;(message), &lt;span style="color:#75715e"&gt;// 接收大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port, &lt;span style="color:#75715e"&gt;// 接收端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE, &lt;span style="color:#75715e"&gt;// 超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL &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:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;==&lt;/span&gt; MACH_MSG_SUCCESS) {
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received: %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, message.data);
&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;return&lt;/span&gt; kr;
&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="设置异常端口"&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-c" data-lang="c"&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;mach/mach.h&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&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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_task_exception_port&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port) {
&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;exception_mask_t&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BREAKPOINT &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_SOFTWARE;
&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:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&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:#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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_exception_ports&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_mask_t&lt;/span&gt; masks[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_TYPES_COUNT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; ports[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_behavior_t&lt;/span&gt; behaviors[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;thread_state_flavor_t&lt;/span&gt; flavors[EXC_TYPES_COUNT];
&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:#a6e22e"&gt;task_get_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ALL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; masks,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;count,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; behaviors,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flavors
&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;hr&gt;
&lt;h2 id="异常处理流程"&gt;异常处理流程&lt;/h2&gt;
&lt;h3 id="完整的异常处理流程"&gt;完整的异常处理流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 硬件检测到异常&lt;br/&gt;CPU执行非法操作，触发硬件中断"] --&gt; B["2. 陷入内核&lt;br/&gt;CPU切换到内核态，执行异常处理程序"]
B --&gt; C["3. 内核构造异常消息&lt;br/&gt;创建包含异常信息的Mach消息"]
C --&gt; D["4. 发送到异常端口&lt;br/&gt;按照 Thread → Task → Host 顺序查找端口"]
D --&gt; E["5. 等待回复&lt;br/&gt;内核暂停线程，等待异常处理程序的回复"]
E --&gt; F{"6. 处理回复"}
F --&gt;|KERN_SUCCESS| G["恢复线程执行"]
F --&gt;|其他| H["转换为Unix信号或终止进程"]
&lt;/pre&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-c" data-lang="c"&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;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; Head;
&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;mach_msg_body_t&lt;/span&gt; msgh_body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&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;mach_msg_port_descriptor_t&lt;/span&gt; task; &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 style="color:#75715e"&gt;// 异常信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception; &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;mach_msg_type_number_t&lt;/span&gt; codeCnt; &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;int64_t&lt;/span&gt; code[&lt;span style="color:#ae81ff"&gt;2&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;} __Request__mach_exception_raise_t;
&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;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; Head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; RetCode; &lt;span style="color:#75715e"&gt;// 返回码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} __Reply__mach_exception_raise_t;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="实现mach异常处理器"&gt;实现Mach异常处理器&lt;/h2&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-c" data-lang="c"&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;mach/mach.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;pthread.h&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&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; exception_thread;
&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;mach_port_t&lt;/span&gt; exception_port;
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; original_exception_port;
&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;exception_behavior_t&lt;/span&gt; original_behavior;
&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;thread_state_flavor_t&lt;/span&gt; original_flavor;
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_exception&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; task,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_exception_data_t&lt;/span&gt; code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; code_count
&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;// 获取线程状态（ARM64架构）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：如需支持x86_64模拟器，需要使用x86_thread_state64_t和X86_THREAD_STATE64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#if defined(__arm64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;arm_thread_state64_t&lt;/span&gt; state;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; state_count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ARM_THREAD_STATE64_COUNT;
&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:#a6e22e"&gt;thread_get_state&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, ARM_THREAD_STATE64,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;thread_state_t&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state_count);
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Exception: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, exception);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Code: 0x%llx, 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, code[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], code[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;PC: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)state.__pc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;LR: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)state.__lr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&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:#75715e"&gt;// collect_backtrace(thread);
&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:#75715e"&gt;// save_crash_log();
&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;return&lt;/span&gt; KERN_FAILURE;
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exception_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&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;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&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;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; task;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; code_count;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int64_t&lt;/span&gt; code[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flavor;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; state_count;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;natural_t&lt;/span&gt; state[&lt;span style="color:#ae81ff"&gt;224&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } request;
&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;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; ret_code;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } reply;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_RCV_LARGE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;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;sizeof&lt;/span&gt;(request),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; MACH_MSG_SUCCESS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_exception&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;.name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.task.name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.exception,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.code_count
&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; reply.head.msgh_bits &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MACH_MSGH_BITS&lt;/span&gt;(MACH_MSG_TYPE_MOVE_SEND_ONCE, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(reply);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; request.head.msgh_remote_port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MACH_PORT_NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Mach IPC惯例：回复消息ID = 请求消息ID + 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; request.head.msgh_id &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.NDR &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NDR_record;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.ret_code &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kr;
&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:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;reply.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_SEND_MSG,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(reply),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&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;return&lt;/span&gt; NULL;
&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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install_exception_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_RIGHT_RECEIVE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_port
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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;exception_mask_t&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BREAKPOINT;
&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;exception_mask_t&lt;/span&gt; masks_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; ports_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_behavior_t&lt;/span&gt; behaviors_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;thread_state_flavor_t&lt;/span&gt; flavors_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_TYPES_COUNT;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_get_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask, &lt;span style="color:#75715e"&gt;// 输入：要查询的异常类型掩码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; masks_out, &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:#f92672"&gt;&amp;amp;&lt;/span&gt;count, &lt;span style="color:#75715e"&gt;// 输入输出：数组大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports_out, &lt;span style="color:#75715e"&gt;// 输出：端口数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; behaviors_out, &lt;span style="color:#75715e"&gt;// 输出：行为数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flavors_out &lt;span style="color:#75715e"&gt;// 输出：flavor数组
&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;if&lt;/span&gt; (count &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_exception_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ports_out[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_behavior &lt;span style="color:#f92672"&gt;=&lt;/span&gt; behaviors_out[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_flavor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; flavors_out[&lt;span style="color:#ae81ff"&gt;0&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_thread, NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_handler_thread, NULL);
&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; KERN_SUCCESS;
&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;p&gt;调试器（如LLDB）通过在Task（任务/进程）级别注册异常端口来优先拦截异常。了解这一机制有助于理解为什么调试时某些崩溃行为会有所不同。&lt;/p&gt;</description></item><item><title>崩溃-信号处理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86/</guid><description>&lt;p&gt;Unix信号是进程间通信和异常通知的重要机制。本文详细介绍Unix信号的基础知识、常见崩溃信号以及Signal Handler的正确实现方式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="unix信号基础"&gt;Unix信号基础&lt;/h2&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-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;┌─────────────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Unix信号 │
&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&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&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;│ • 用户输入（如Ctrl+C） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 系统调用（如kill） │
&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;pre class="mermaid"&gt;flowchart TD
A["1. 信号产生（Generation）&lt;br/&gt;某个事件触发信号的产生"]
--&gt; B["2. 信号投递（Delivery）&lt;br/&gt;信号被投递到目标进程&lt;br/&gt;此时信号处于pending状态"]
--&gt; C["3. 信号处理（Handling）&lt;br/&gt;进程响应信号，执行以下之一"]
C --&gt; D["执行默认动作"]
C --&gt; E["执行自定义处理函数"]
C --&gt; F["忽略信号"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="常见信号类型"&gt;常见信号类型&lt;/h2&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;编号(macOS/iOS)&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;SIGABRT&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;调用abort()产生&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGBUS&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;总线错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGFPE&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;算术异常&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGILL&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;非法指令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGSEGV&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;段错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGTRAP&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;断点陷阱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGSYS&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;非法系统调用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SIGKILL&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;强制终止（不可捕获）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGTERM&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;请求终止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGINT&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;中断（Ctrl+C）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGQUIT&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;退出（Ctrl+\）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGPIPE&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;管道破裂&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGALRM&lt;/td&gt;
&lt;td&gt;14&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;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-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGABRT (6)
&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;• 调用abort()函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 未捕获的NSException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• C++ exception未处理
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• assert失败（某些情况）
&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&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;SIGSEGV (11)
&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&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;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_ACCESS (KERN_INVALID_ADDRESS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_ACCESS (KERN_PROTECTION_FAILURE)
&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;SIGBUS (10)
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• mmap映射失效
&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;与SIGSEGV的区别：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• SIGSEGV: 虚拟地址层面的问题（地址未映射或权限不足）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• SIGBUS: 物理地址层面的问题（对齐错误、硬件问题等）
&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;SIGILL (4)
&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;• Swift强制解包nil
&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;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_INSTRUCTION
&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;SIGFPE (8)
&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&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;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_ARITHMETIC
&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;SIGTRAP (5)
&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;• Swift的fatalError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• precondition失败
&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;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BREAKPOINT
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="signal-handler"&gt;Signal Handler&lt;/h2&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-c" data-lang="c"&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;signal.h&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&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;simple_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig) {
&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:#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;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_simple_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;(SIGSEGV, simple_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;(SIGABRT, simple_handler);
&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="使用sigaction推荐"&gt;使用sigaction（推荐）&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-c" data-lang="c"&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;signal.h&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&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;detailed_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// sig: 信号编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// info: 信号详细信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// context: 上下文（包含寄存器状态）
&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;// 使用sigaction注册
&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;setup_sigaction_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&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:#a6e22e"&gt;memset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(action));
&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; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; detailed_handler;
&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; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#75715e"&gt;// 使用sa_sigaction而非sa_handler
&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; SA_ONSTACK; &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 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:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&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:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGABRT, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGBUS, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGFPE, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGILL, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGTRAP, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&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="siginfo_t结构"&gt;siginfo_t结构&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_signo; &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;int&lt;/span&gt; si_errno; &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;int&lt;/span&gt; si_code; &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;pid_t&lt;/span&gt; si_pid; &lt;span style="color:#75715e"&gt;// 发送信号的进程ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uid_t&lt;/span&gt; si_uid; &lt;span style="color:#75715e"&gt;// 发送信号的用户ID
&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:#f92672"&gt;*&lt;/span&gt;si_addr; &lt;span style="color:#75715e"&gt;// 故障地址（SIGSEGV/SIGBUS）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_status; &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:#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;siginfo_t&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;// 解析siginfo
&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;parse_siginfo&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Signal: %d (%s)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, sig, &lt;span style="color:#a6e22e"&gt;strsignal&lt;/span&gt;(sig));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Code: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code);
&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;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGSEGV &lt;span style="color:#f92672"&gt;||&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGBUS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Fault address: %p&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_addr);
&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;switch&lt;/span&gt; (sig) {
&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; SIGSEGV:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code) {
&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; SEGV_MAPERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Address not mapped&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&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;break&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; SEGV_ACCERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid permissions&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&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;break&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;break&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; SIGBUS:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code) {
&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; BUS_ADRALN:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid address alignment&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&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;break&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; BUS_ADRERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Nonexistent physical address&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&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;break&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;break&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&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="为什么需要备用栈"&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-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;当栈溢出时：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 栈空间已耗尽
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 系统发送SIGSEGV信号
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 信号处理函数需要栈空间来执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 但是栈已经溢出了！
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5. 信号处理函数无法执行
&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;使用备用信号栈（Alternate Signal Stack）
&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-c" data-lang="c"&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;signal.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;stdlib.h&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&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;setup_alternate_stack&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&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:#f92672"&gt;*&lt;/span&gt;stack &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(SIGSTKSZ);
&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; (stack &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL) {
&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&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;stack_t&lt;/span&gt; ss;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_sp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; stack;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SIGSTKSZ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;sigaltstack&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ss, NULL) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;(stack);
&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&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;// 注册信号处理器时使用SA_ONSTACK标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&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:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&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="什么是异步信号安全"&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-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;异步信号安全（Async-Signal-Safe）：
&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;• 可能在malloc中间被打断
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能在printf中间被打断
&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&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;因此，信号处理函数只能调用&amp;#34;异步信号安全&amp;#34;的函数
&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-c" data-lang="c"&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&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:#a6e22e"&gt;write&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fsync&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:#a6e22e"&gt;_exit&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_Exit&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abort&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kill&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;getpid&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:#a6e22e"&gt;signal&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigprocmask&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigfillset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigdelset&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;// 其他（注意：以下函数不在POSIX异步信号安全列表中，但大多数实现是安全的）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// 大多数实现安全，但非POSIX标准
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// 大多数实现安全，但非POSIX标准
&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-c" data-lang="c"&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&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:#a6e22e"&gt;malloc&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;realloc&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;new &lt;span style="color:#f92672"&gt;/&lt;/span&gt; delete
&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;// 标准I/O
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fprintf&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fclose&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;// Objective-C
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;objc_msgSend&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;NSLog&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;任何&lt;/span&gt;OC方法调用
&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++
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;大多数&lt;/span&gt;C&lt;span style="color:#f92672"&gt;++&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;标准库函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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:#a6e22e"&gt;syslog&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;strtok&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;localtime&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="实现示例"&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-c" data-lang="c"&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;signal.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;execinfo.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;unistd.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;fcntl.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;string.h&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&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; kFatalSignals[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGABRT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGBUS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGFPE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGILL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGSEGV,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGTRAP,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGSYS,
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; kFatalSignalsCount &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(kFatalSignals) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(kFatalSignals[&lt;span style="color:#ae81ff"&gt;0&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction g_originalActions[&lt;span style="color:#ae81ff"&gt;32&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; g_crashLogPath[&lt;span style="color:#ae81ff"&gt;1024&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;volatile&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sig_atomic_t&lt;/span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str) {
&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; (str) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(fd, str, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;(str));
&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:#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; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; value) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; buffer[&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\0&amp;#39;&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;int&lt;/span&gt; negative &lt;span style="color:#f92672"&gt;=&lt;/span&gt; value &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;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;if&lt;/span&gt; (negative) value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;value;
&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;do&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;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;/=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;if&lt;/span&gt; (negative) &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&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:#a6e22e"&gt;write&lt;/span&gt;(fd, ptr, buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ptr);
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; value) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; buffer[&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\0&amp;#39;&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; hex[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0123456789abcdef&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;do&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;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hex[value &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xf&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&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;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&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:#a6e22e"&gt;write&lt;/span&gt;(fd, ptr, buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ptr);
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;crash_signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&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;if&lt;/span&gt; (g_handling) {
&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&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; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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;int&lt;/span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;(g_crashLogPath, O_WRONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_CREAT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_TRUNC, &lt;span style="color:#ae81ff"&gt;0644&lt;/span&gt;);
&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; (fd &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 无法打开文件，尝试写入stderr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; STDERR_FILENO;
&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:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;=== Crash Report ===&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Signal: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34; (&amp;#34;&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;switch&lt;/span&gt; (sig) {
&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; SIGABRT: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGABRT&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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; SIGBUS: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGBUS&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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; SIGFPE: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGFPE&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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; SIGILL: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGILL&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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; SIGSEGV: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGSEGV&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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; SIGTRAP: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGTRAP&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;UNKNOWN&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&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:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&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:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Code: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&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;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGSEGV &lt;span style="color:#f92672"&gt;||&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGBUS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Fault Address: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(fd, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&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:#75715e"&gt;// 注意：backtrace()严格来说也不是异步信号安全的函数
&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:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Backtrace:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&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;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;callstack[&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; frames &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;backtrace&lt;/span&gt;(callstack, &lt;span style="color:#ae81ff"&gt;128&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;// 注意：backtrace_symbols使用malloc，不是异步安全的
&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;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; frames; i&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:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(fd, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)callstack[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&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;if&lt;/span&gt; (fd &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; STDERR_FILENO) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fsync&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(fd);
&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:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig], NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;(sig);
&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;install_crash_signal_handlers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logPath) {
&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:#a6e22e"&gt;strncpy&lt;/span&gt;(g_crashLogPath, logPath, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(g_crashLogPath) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; alternate_stack[SIGSTKSZ];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;stack_t&lt;/span&gt; ss;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_sp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; alternate_stack;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SIGSTKSZ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaltstack&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ss, NULL);
&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;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(action));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; crash_signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&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;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; kFatalSignalsCount; i&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:#66d9ef"&gt;int&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kFatalSignals[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig]);
&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:#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;uninstall_crash_signal_handlers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; kFatalSignalsCount; i&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:#66d9ef"&gt;int&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kFatalSignals[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig], NULL);
&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;hr&gt;
&lt;h2 id="获取上下文信息"&gt;获取上下文信息&lt;/h2&gt;
&lt;h3 id="从ucontext获取寄存器"&gt;从ucontext获取寄存器&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-c" data-lang="c"&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;signal.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;sys/ucontext.h&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&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;signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;uc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context;
&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;#if defined(__arm64__) || defined(__aarch64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ARM64架构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; uc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&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;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;; i&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;x%d: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, i, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__x[i]);
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;fp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__fp); &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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;lr: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__lr); &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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;sp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__sp); &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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pc: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__pc); &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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;cpsr: 0x%x&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__cpsr); &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 style="color:#75715e"&gt;#elif defined(__x86_64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// x86_64架构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; uc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rax: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rax);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rbx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rbx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rcx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rcx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rdx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rdx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rsi: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rsi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rdi: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rdi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rbp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rbp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rsp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rsp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rip: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rip);
&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;#endif
&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-c" data-lang="c"&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;backtrace_from_context&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&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;#if defined(__arm64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; pc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__pc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__fp;
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Backtrace:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;0: 0x%lx (PC)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)pc);
&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;int&lt;/span&gt; frame &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (fp &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; frame &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ARM64栈帧布局：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// [fp+0]: 上一帧的fp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// [fp+8]: 返回地址
&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;uintptr_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;frame_ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)fp;
&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;if&lt;/span&gt; ((&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)frame_ptr &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x1000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&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;uintptr_t&lt;/span&gt; return_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frame_ptr[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%d: 0x%lx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, frame, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)return_addr);
&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; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frame_ptr[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frame&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&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;hr&gt;
&lt;h2 id="信号掩码"&gt;信号掩码&lt;/h2&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-c" data-lang="c"&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;signal.h&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&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;block_signals&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&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:#a6e22e"&gt;sigprocmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&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&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:#a6e22e"&gt;sigprocmask&lt;/span&gt;(SIG_UNBLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&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;setup_handler_with_mask&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO;
&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;// 在处理SIGSEGV时阻塞其他信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigfillset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&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:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&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-c" data-lang="c"&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;check_pending_signals&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; pending;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigpending&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pending);
&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;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;sigismember&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pending, SIGINT)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SIGINT is pending&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&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;hr&gt;
&lt;h2 id="信号与多线程"&gt;信号与多线程&lt;/h2&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-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;1. 信号处理器是进程级的
&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;2. 信号掩码是线程级的
&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; • pthread_sigmask()用于设置线程的信号掩码
&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;3. 信号投递
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 同步信号（如SIGSEGV）投递给触发它的线程
&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-c" data-lang="c"&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;pthread.h&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:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&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&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;setup_thread_signal_mask&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGPIPE); &lt;span style="color:#75715e"&gt;// 阻塞SIGPIPE
&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:#a6e22e"&gt;pthread_sigmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&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:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;signal_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&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;int&lt;/span&gt; sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&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:#a6e22e"&gt;sigwait&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;sig);
&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:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received signal: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, sig);
&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;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGTERM) {
&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;break&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&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;setup_signal_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&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;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_sigmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&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;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, signal_handler_thread, NULL);
&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="信号处理器中的死锁"&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-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;场景：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 主线程调用malloc()，获取了内存分配锁
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 此时收到SIGSEGV信号
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 信号处理器中调用malloc()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 尝试获取同一把锁 -&amp;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&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-c" data-lang="c"&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:#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 style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;volatile&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sig_atomic_t&lt;/span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&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;if&lt;/span&gt; (g_handling) {
&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;return&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; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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&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:#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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="与其他sdk的冲突"&gt;与其他SDK的冲突&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-c" data-lang="c"&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:#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; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction g_original_action;
&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;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my_signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&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:#a6e22e"&gt;handle_crash&lt;/span&gt;(sig, info, context);
&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;if&lt;/span&gt; (g_original_action.sa_flags &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; SA_SIGINFO) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.&lt;span style="color:#a6e22e"&gt;sa_sigaction&lt;/span&gt;(sig, info, context);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (g_original_action.sa_handler &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SIG_DFL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.sa_handler &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SIG_IGN) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.&lt;span style="color:#a6e22e"&gt;sa_handler&lt;/span&gt;(sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&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:#a6e22e"&gt;signal&lt;/span&gt;(sig, SIG_DFL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;(sig);
&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;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; my_signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&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:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_original_action);
&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="信号与mach异常的关系"&gt;信号与Mach异常的关系&lt;/h2&gt;
&lt;h3 id="转换关系"&gt;转换关系&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph Mach["Mach异常"]
A1[EXC_BAD_ACCESS]
A2[EXC_BAD_INSTRUCTION]
A3[EXC_ARITHMETIC]
A4[EXC_BREAKPOINT]
A5[EXC_CRASH]
A6[EXC_SOFTWARE]
end
subgraph Signal["Unix信号"]
B1[SIGSEGV / SIGBUS]
B2[SIGILL]
B3[SIGFPE]
B4[SIGTRAP]
B5[SIGABRT]
B6[取决于具体代码]
end
A1 --&gt; B1
A2 --&gt; B2
A3 --&gt; B3
A4 --&gt; B4
A5 --&gt; B5
A6 --&gt; B6
&lt;/pre&gt;
&lt;p&gt;转换时机：&lt;/p&gt;</description></item><item><title>崩溃-原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/</link><pubDate>Sun, 10 May 2026 22:25:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;理解崩溃的底层原理是有效治理的基础。本文详细介绍iOS的异常处理机制、崩溃的传递链路以及各类崩溃的本质原因。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="ios异常处理架构"&gt;iOS异常处理架构&lt;/h2&gt;
&lt;p&gt;iOS的异常处理采用分层架构，从底层到上层依次为：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart BT
subgraph ARCH["异常处理架构"]
direction BT
HW["硬件层 (Hardware)&lt;br/&gt;CPU异常、内存访问违规、非法指令"]
MACH["Mach层 (Mach Exception)&lt;br/&gt;EXC_BAD_ACCESS、EXC_BAD_INSTRUCTION、EXC_CRASH"]
BSD["BSD层 (Unix Signal)&lt;br/&gt;SIGABRT、SIGSEGV、SIGBUS、SIGFPE、SIGILL"]
APP["应用层 (Application Layer)&lt;br/&gt;NSException、@try-@catch、Swift Error"]
HW --&gt; MACH
MACH --&gt; BSD
BSD --&gt; APP
end
&lt;/pre&gt;
&lt;p&gt;需要注意：这张图表示崩溃治理中常见的异常/终止机制层次，并不表示所有异常都一定从硬件层逐级向上传递。&lt;code&gt;NSException&lt;/code&gt; 属于 Objective-C 运行时/框架层的语言异常机制，不是内核产生的 Mach 异常。只有当 &lt;code&gt;NSException&lt;/code&gt; 未被捕获时，运行时最终通常会调用 &lt;code&gt;abort()&lt;/code&gt; 主动终止进程，随后表现为 &lt;code&gt;SIGABRT&lt;/code&gt; / &lt;code&gt;EXC_CRASH&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="崩溃的传递链路"&gt;崩溃的传递链路&lt;/h2&gt;
&lt;p&gt;当异常发生时，会按照特定的链路传递：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 硬件触发异常&lt;br/&gt;CPU检测到非法操作（如访问无效内存地址）&lt;br/&gt;触发硬件中断，陷入内核态"] --&gt; B["2. Mach层处理&lt;br/&gt;内核将硬件异常转换为Mach异常&lt;br/&gt;通过异常端口发送给用户态的异常处理程序&lt;br/&gt;如果没有处理，转换为Unix信号"]
B --&gt; C["3. BSD层处理&lt;br/&gt;Mach异常被转换为对应的Unix信号&lt;br/&gt;调用进程注册的Signal Handler&lt;br/&gt;如果没有处理或处理后继续，执行默认行为"]
C --&gt; D["4. 进程终止&lt;br/&gt;默认行为通常是终止进程&lt;br/&gt;生成崩溃日志"]
&lt;/pre&gt;
&lt;h3 id="mach异常与unix信号的对应关系"&gt;Mach异常与Unix信号的对应关系&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mach异常&lt;/th&gt;
&lt;th&gt;Unix信号&lt;/th&gt;
&lt;th&gt;触发原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BAD_ACCESS&lt;/td&gt;
&lt;td&gt;SIGSEGV/SIGBUS&lt;/td&gt;
&lt;td&gt;访问无效内存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BAD_INSTRUCTION&lt;/td&gt;
&lt;td&gt;SIGILL&lt;/td&gt;
&lt;td&gt;非法指令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_ARITHMETIC&lt;/td&gt;
&lt;td&gt;SIGFPE&lt;/td&gt;
&lt;td&gt;算术异常（如除零）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BREAKPOINT&lt;/td&gt;
&lt;td&gt;SIGTRAP&lt;/td&gt;
&lt;td&gt;断点/调试陷阱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_CRASH&lt;/td&gt;
&lt;td&gt;SIGABRT&lt;/td&gt;
&lt;td&gt;程序主动abort&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="mach异常机制"&gt;Mach异常机制&lt;/h2&gt;
&lt;h3 id="mach内核简介"&gt;Mach内核简介&lt;/h3&gt;
&lt;p&gt;Mach是macOS/iOS的微内核，提供了最基础的系统服务：&lt;/p&gt;</description></item><item><title>崩溃-治理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/</guid><description>&lt;p&gt;本文详细介绍常见崩溃类型的修复方法、防崩溃保护机制以及线上监控体系。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;崩溃治理是 APM 稳定性子系的核心模块。完整的监控建设、多类型稳定性问题（Watchdog/OOM/CPU/IO）的统一治理与 Zombie/Coredump/MemoryGraph 等高级归因能力，请参考 &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/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/"&gt;业界方案&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="崩溃治理流程"&gt;崩溃治理流程&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph S1[1. 崩溃发现]
A1[线上监控报警]
A2[用户反馈]
A3[测试发现]
end
subgraph S2[2. 崩溃分析]
B1[符号化堆栈]
B2[问题定位]
B3[根因分析]
end
subgraph S3[3. 问题修复]
C1[代码修复]
C2[防护措施]
C3[回归测试]
end
subgraph S4[4. 效果验证]
D1[灰度发布]
D2[监控崩溃率]
D3[持续跟踪]
end
A1 --&gt; S2
A2 --&gt; S2
A3 --&gt; S2
S2 --&gt; S3
S3 --&gt; S4
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="常见崩溃类型及修复"&gt;常见崩溃类型及修复&lt;/h2&gt;
&lt;h3 id="1-数组越界"&gt;1. 数组越界&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-objc" data-lang="objc"&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;NSArray &lt;span style="color:#f92672"&gt;*&lt;/span&gt;array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;@[&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;@1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;@2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;@3&lt;/span&gt;&lt;span style="color:#ae81ff"&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;id&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; array[&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// NSRangeException
&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;// 修复方案1：边界检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeObjectAtIndex:&lt;/span&gt;(NSUInteger)index &lt;span style="color:#a6e22e"&gt;fromArray:&lt;/span&gt;(NSArray &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)array {
&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; (index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; array.count) {
&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; array[index];
&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; nil;
&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;// 修复方案2：分类安全方法
&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;NSArray&lt;/span&gt; (Safe)
&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;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeObjectAtIndex:&lt;/span&gt;(NSUInteger)index {
&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; (index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; self.count) {
&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; [self objectAtIndex:index];
&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; nil;
&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;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;// 修复方案3：Swift可选绑定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension Array {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subscript(safe index: Index) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Element&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:#66d9ef"&gt;return&lt;/span&gt; indices.contains(index) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; self[index] &lt;span style="color:#f92672"&gt;:&lt;/span&gt; nil
&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:#75715e"&gt;// 使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; array[safe: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 返回nil而不是崩溃
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-字典插入nil"&gt;2. 字典插入nil&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-objc" data-lang="objc"&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;NSMutableDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSMutableDictionary dictionary];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[dict setObject:value forKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;key&amp;#34;&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// NSInvalidArgumentException
&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;// 修复方案1：nil检查
&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;setObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object &lt;span style="color:#a6e22e"&gt;forKey:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)key &lt;span style="color:#a6e22e"&gt;inDict:&lt;/span&gt;(NSMutableDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)dict {
&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; (object &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dict[key] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; object;
&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:#75715e"&gt;// 修复方案2：分类安全方法
&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;NSMutableDictionary&lt;/span&gt; (Safe)
&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;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeSetObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object &lt;span style="color:#a6e22e"&gt;forKey:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)key {
&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; (object &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setObject:object forKey:key];
&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;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;// 修复方案3：使用NSNull
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dict[&lt;span style="color:#e6db74"&gt;@&amp;#34;key&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; value &lt;span style="color:#f92672"&gt;?:&lt;/span&gt; [NSNull null];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-unrecognized-selector"&gt;3. Unrecognized Selector&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-objc" data-lang="objc"&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;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str &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;[str performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(count)]; &lt;span style="color:#75715e"&gt;// unrecognized selector
&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;// 修复方案1：respondsToSelector检查
&lt;/span&gt;&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; ([obj respondsToSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(someMethod)]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [obj performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(someMethod)];
&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;// 修复方案2：消息转发防护
&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;NSObject&lt;/span&gt; (CrashProtection)
&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;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;// Hook forwardingTargetForSelector:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method original &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(forwardingTargetForSelector:));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method swizzled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(safe_forwardingTargetForSelector:));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method_exchangeImplementations(original, swizzled);
&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;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safe_forwardingTargetForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&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;id&lt;/span&gt; target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [self safe_forwardingTargetForSelector:aSelector];
&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; (target) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; target;
&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; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Unrecognized selector: %@ on %@&amp;#34;&lt;/span&gt;, NSStringFromSelector(aSelector), self);
&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;return&lt;/span&gt; [CrashStub 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&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;h3 id="4-kvo崩溃"&gt;4. KVO崩溃&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-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景1：重复移除观察者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;value&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;value&amp;#34;&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景2：未移除观察者就释放
&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;dealloc&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&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;// 修复方案：安全的KVO封装
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SafeKVOProxy&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;NSObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; observer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;keyPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;callback)(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; newValue);
&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;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;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SafeKVOProxy&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;instancetype&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initWithTarget:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)target
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;keyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;observer:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)observer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;))callback {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super init];
&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; (self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _keyPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; keyPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _observer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; observer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _callback &lt;span style="color:#f92672"&gt;=&lt;/span&gt; callback;
&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; [target addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
&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; self;
&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;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;observeValueForKeyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ofObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;change:&lt;/span&gt;(NSDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)change
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context {
&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; (self.callback) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.callback(change[NSKeyValueChangeNewKey]);
&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;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;dealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [_target removeObserver:self forKeyPath:_keyPath];
&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;h3 id="5-多线程崩溃"&gt;5. 多线程崩溃&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-objc" data-lang="objc"&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:#75715e"&gt;// 线程1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[mutableArray addObject:obj1];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 线程2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[mutableArray removeObjectAtIndex:&lt;span style="color:#ae81ff"&gt;0&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：加锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;strong&lt;/span&gt;) NSLock &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arrayLock;
&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;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeAddObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.arrayLock lock];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.mutableArray addObject:object];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.arrayLock unlock];
&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;// 修复方案2：使用GCD串行队列
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;strong&lt;/span&gt;) dispatch_queue_t arrayQueue;
&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;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeAddObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_sync(self.arrayQueue, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.mutableArray addObject:object];
&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:#75715e"&gt;// 修复方案3：使用Actor（Swift Concurrency）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;actor SafeStorage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; private var items: [Any] &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; func append(_ item: Any) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items.append(item)
&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; func remove(at index: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; guard index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; items.count &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items.remove(at: index)
&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; func getAll() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; [Any] {
&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; items
&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;let storage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SafeStorage()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;await storage.append(obj1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-野指针崩溃"&gt;6. 野指针崩溃&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-objc" data-lang="objc"&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;__unsafe_unretained &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; unsafeRef &lt;span style="color:#f92672"&gt;=&lt;/span&gt; obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[unsafeRef description]; &lt;span style="color:#75715e"&gt;// EXC_BAD_ACCESS
&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;// 修复方案1：使用weak而非unsafe_unretained
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;__weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; weakRef &lt;span style="color:#f92672"&gt;=&lt;/span&gt; obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[weakRef description]; &lt;span style="color:#75715e"&gt;// 安全，weakRef为nil
&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;// 修复方案2：Zombie Objects检测（调试用）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在Scheme中启用Zombie Objects
&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;// 修复方案3：野指针检测工具
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用Address Sanitizer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Product -&amp;gt; Scheme -&amp;gt; Edit Scheme -&amp;gt; Diagnostics -&amp;gt; Address Sanitizer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-swift强制解包崩溃"&gt;7. Swift强制解包崩溃&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:#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;let&lt;/span&gt; value: String? = &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;print(value!) &lt;span style="color:#75715e"&gt;// Fatal error: Unexpectedly found nil&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;// 修复方案1：可选绑定&lt;/span&gt;
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value = optionalValue {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(value)
&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;// 修复方案2：空合运算符&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; value = optionalValue ?? &lt;span style="color:#e6db74"&gt;&amp;#34;default&amp;#34;&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;// 修复方案3：guard语句&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value = optionalValue &lt;span style="color:#66d9ef"&gt;else&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&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;print(value)
&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;// 修复方案4：可选链&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; length = optionalString?.count &lt;span style="color:#75715e"&gt;// 返回Int?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="8-oomout-of-memory崩溃"&gt;8. OOM（Out Of Memory）崩溃&lt;/h3&gt;
&lt;p&gt;OOM 是 iOS 最难治理的崩溃类型之一：系统因进程占用内存超过限制而将其强杀，不会产生标准崩溃日志，App 也没有机会在崩溃现场同步写下详细堆栈。因此 OOM 治理必须&lt;strong&gt;在事故前就把现场数据预埋下来&lt;/strong&gt;，分为三个时段：&lt;/p&gt;</description></item><item><title>崩溃-采集</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/</link><pubDate>Sun, 21 Jun 2026 22:41:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/</guid><description>&lt;p&gt;准确采集崩溃信息是分析和修复问题的前提。本文详细介绍iOS崩溃的捕获方案、堆栈回溯技术以及符号化原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="崩溃采集架构"&gt;崩溃采集架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph capture["崩溃捕获层"]
direction LR
mach["Mach Exception Handler"]
signal["Unix Signal Handler"]
exception["NSException Handler"]
end
subgraph collect["信息采集层"]
direction LR
backtrace["堆栈回溯(Backtrace)"]
register["寄存器状态"]
thread["线程信息"]
device["设备/应用信息"]
end
subgraph storage["本地存储层"]
direction LR
async_write["异步安全写入"]
file_manage["崩溃文件管理"]
end
subgraph report["上报处理层"]
direction LR
symbolicate["符号化解析"]
aggregate["崩溃聚合"]
analyze["数据分析"]
end
capture --&gt; collect
collect --&gt; storage
storage --&gt; report
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="mach异常捕获"&gt;Mach异常捕获&lt;/h2&gt;
&lt;p&gt;Mach是macOS/iOS的内核，提供了底层的异常处理机制。Mach异常是最底层的异常类型，发生在内核态，比Unix信号更早被触发。通过注册Mach异常处理器，可以在信号处理之前捕获到崩溃信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心概念&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mach Port（端口）&lt;/strong&gt;：Mach内核中进程间通信（IPC）的基本单元，类似于文件描述符&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exception Port（异常端口）&lt;/strong&gt;：专门用于接收异常消息的端口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task&lt;/strong&gt;：Mach中的任务概念，对应一个进程，包含地址空间和资源&lt;/li&gt;
&lt;/ul&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-c" data-lang="c"&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;mach/mach.h&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&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exception_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)arg;
&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;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&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;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; body;
&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; } request;
&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;mach_msg_return_t&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_RCV_LARGE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;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;sizeof&lt;/span&gt;(request),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&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;if&lt;/span&gt; (result &lt;span style="color:#f92672"&gt;==&lt;/span&gt; MACH_MSG_SUCCESS) {
&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:#a6e22e"&gt;handle_exception&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request);
&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;return&lt;/span&gt; NULL;
&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;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register_exception_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_RIGHT_RECEIVE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_port
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt; EXC_MASK_BREAKPOINT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&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;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&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;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, exception_handler_thread,
&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:#f92672"&gt;*&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)exception_port);
&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; KERN_SUCCESS;
&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="mach异常处理流程"&gt;Mach异常处理流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 异常发生"] --&gt; B["2. 内核发送异常消息到异常端口"]
B --&gt; C["3. 异常处理线程接收消息"]
C --&gt; D["4. 解析异常信息"]
D --&gt; D1["exception type"]
D --&gt; D2["exception code"]
D --&gt; D3["thread state"]
D1 &amp; D2 &amp; D3 --&gt; E["5. 采集崩溃信息"]
E --&gt; E1["堆栈回溯"]
E --&gt; E2["寄存器状态"]
E --&gt; E3["其他上下文"]
E1 &amp; E2 &amp; E3 --&gt; F["6. 保存崩溃日志"]
F --&gt; G["7. 决定后续处理"]
G --&gt; G1["转发给原异常处理器"]
G --&gt; G2["让进程终止"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="unix信号捕获"&gt;Unix信号捕获&lt;/h2&gt;
&lt;p&gt;Unix信号（Signal）是操作系统向进程发送的异步通知机制。当发生特定事件（如非法内存访问、算术错误等）时，内核会向进程发送相应的信号。iOS中，Mach异常通常会被转换为对应的Unix信号。&lt;/p&gt;</description></item><item><title>崩溃</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83/</link><pubDate>Mon, 04 May 2026 10:37:14 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83/</guid><description>&lt;p&gt;崩溃是影响App稳定性的最严重问题。当应用发生崩溃时，用户会被强制退出应用，严重影响用户体验和产品口碑。&lt;/p&gt;
&lt;p&gt;本系列文章系统性地介绍iOS崩溃的原理、采集方案以及治理策略。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什么是崩溃"&gt;什么是崩溃&lt;/h2&gt;
&lt;p&gt;崩溃（Crash）是指应用程序因为异常或错误而被强制终止的现象。从技术角度看，崩溃可以分为以下几类：&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;Mach异常&lt;/td&gt;
&lt;td&gt;底层硬件/内核异常&lt;/td&gt;
&lt;td&gt;访问无效内存、除零错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unix信号&lt;/td&gt;
&lt;td&gt;系统信号导致进程终止&lt;/td&gt;
&lt;td&gt;SIGABRT、SIGSEGV、SIGBUS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSException&lt;/td&gt;
&lt;td&gt;OC层未捕获的异常&lt;/td&gt;
&lt;td&gt;数组越界、unrecognized selector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内存问题&lt;/td&gt;
&lt;td&gt;OOM或内存损坏&lt;/td&gt;
&lt;td&gt;内存不足、野指针&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watchdog&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;p&gt;崩溃率是衡量App稳定性的核心指标：&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;1. 崩溃用户率（推荐）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃用户率 = 发生崩溃的用户数 / 总活跃用户数 × 100%
&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;2. 崩溃次数率
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃次数率 = 崩溃次数 / 启动次数 × 100%
&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;3. 崩溃Session率
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃Session率 = 崩溃Session数 / 总Session数 × 100%
&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;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;├─────────────────────────────────────────────────────────────┤
&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;│ │ Mach异常 / Unix信号 / NSException / OOM │ │
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • Mach异常处理 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • Signal Handler │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • NSSetUncaughtExceptionHandler │ │
&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&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&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&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;│ │ • 避免使用OC/Swift API │ │
&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&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&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;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item><item><title>崩溃日志解读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</guid><description>&lt;p&gt;iOS 崩溃日志（&lt;code&gt;.ips&lt;/code&gt; / 老版 &lt;code&gt;.crash&lt;/code&gt;）是排查线上问题的一手证据。它不仅记录了&amp;quot;谁崩了&amp;quot;，更隐藏着&lt;strong&gt;异常类型、终止命名空间、寄存器现场、线程堆栈、二进制映射、资源限额&lt;/strong&gt;等多维度事实。看懂每一个字段，才能把&amp;quot;不能复现&amp;quot;的崩溃拆成&amp;quot;寄存器 x0 是 nil 的后果&amp;quot;这种可复现假设。&lt;/p&gt;
&lt;p&gt;本文聚焦系统生成的崩溃日志本身：格式演变、&lt;code&gt;bug_type&lt;/code&gt; 全景、Header/Body 逐字段、Exception Type / Termination Namespace 深度解读、寄存器视角、符号化工具链、实战案例库、自动化脚本。OOM 专用的 JetsamEvent 日志见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/"&gt;JetsamEvent 日志解读&lt;/a&gt;；崩溃采集与治理方法论见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/"&gt;崩溃-采集&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/"&gt;崩溃-治理&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-ips--crash-格式演变"&gt;1. &lt;code&gt;.ips&lt;/code&gt; / &lt;code&gt;.crash&lt;/code&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;iOS 13 及以前&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.crash&lt;/code&gt; / &lt;code&gt;.ips&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;类 plist 纯文本&lt;/td&gt;
&lt;td&gt;Key-Value 混排，人眼可读但难解析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS 14+&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.ips&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;双段 JSON&lt;/strong&gt;（Header JSON + Body JSON，以换行分隔）&lt;/td&gt;
&lt;td&gt;机器可解析，字段更标准化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode Organizer 导出&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.crash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;纯文本渲染视图&lt;/td&gt;
&lt;td&gt;由 &lt;code&gt;.ips&lt;/code&gt; 通过 &lt;code&gt;CrashReporter.framework&lt;/code&gt; 渲染而来&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;解析规则和 JetsamEvent 完全一致——第一行是 Header JSON，剩余部分是 Body JSON，不能整体 parse。iOS 14+ &lt;code&gt;.ips&lt;/code&gt; 内容可用 &lt;code&gt;log show --archive&lt;/code&gt; 或 Xcode Organizer 转为旧式可读文本，但&lt;strong&gt;字段原始数据始终在 JSON 里&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>卡顿-TableView优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-tableview%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/stutter-tableview%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;列表滚动是用户最敏感的交互场景之一。本文介绍UITableView和UICollectionView的性能优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="列表卡顿的常见原因"&gt;列表卡顿的常见原因&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph frame["每一帧（16.67ms内）需要完成"]
A["1. 计算可见Cell"] --&gt; B["2. 复用或创建Cell"]
B --&gt; C["3. 配置Cell内容"]
C --&gt; C1["设置文本"]
C --&gt; C2["加载图片"]
C --&gt; C3["计算布局"]
C --&gt; C4["渲染视图"]
C1 --&gt; D["4. 提交渲染"]
C2 --&gt; D
C3 --&gt; D
C4 --&gt; D
end
D --&gt; E["⚠️ 任何一步超时都会导致掉帧"]
&lt;/pre&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;高度计算慢&lt;/td&gt;
&lt;td&gt;复杂布局、Auto Layout&lt;/td&gt;
&lt;td&gt;滚动卡顿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cell配置慢&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;未正确注册、identifier错误&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;GPU瓶颈&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;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="cell复用机制"&gt;Cell复用机制&lt;/h2&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OptimizedTableViewController&lt;/span&gt;: UITableViewController {
&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;let&lt;/span&gt; cellIdentifier = &lt;span style="color:#e6db74"&gt;&amp;#34;OptimizedCell&amp;#34;&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&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;// 注册Cell类（推荐）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.register(OptimizedCell.&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;, forCellReuseIdentifier: cellIdentifier)
&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;// 或注册Nib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// tableView.register(UINib(nibName: &amp;#34;OptimizedCell&amp;#34;, bundle: nil), forCellReuseIdentifier: cellIdentifier)&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, cellForRowAt indexPath: IndexPath) -&amp;gt; UITableViewCell {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用dequeueReusableCell（带indexPath的版本会自动创建）&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; cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: indexPath) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt;! OptimizedCell
&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;// 配置Cell&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; item = items[indexPath.row]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cell.configure(with: item)
&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; cell
&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="cell的prepareforreuse"&gt;Cell的prepareForReuse&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OptimizedCell&lt;/span&gt;: UITableViewCell {
&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;let&lt;/span&gt; titleLabel = UILabel()
&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;let&lt;/span&gt; avatarImageView = OptimizedImageView()
&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; currentTask: URLSessionTask?
&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prepareForReuse&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.prepareForReuse()
&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; titleLabel.text = &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; avatarImageView.image = &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;
&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; currentTask?.cancel()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currentTask = &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; avatarImageView.cancelLoading()
&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;configure&lt;/span&gt;(with item: Item) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; titleLabel.text = item.title
&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; avatarImageView.setImage(from: item.avatarURL, placeholder: UIImage(named: &lt;span style="color:#e6db74"&gt;&amp;#34;placeholder&amp;#34;&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;hr&gt;
&lt;h2 id="高度缓存"&gt;高度缓存&lt;/h2&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:#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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, heightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&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; item = items[indexPath.row]
&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; calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item) &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="解决方案1预计算并缓存"&gt;解决方案1：预计算并缓存&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeightCachedTableViewController&lt;/span&gt;: UITableViewController {
&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; items: [Item] = []
&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; heightCache: [IndexPath: CGFloat] = [:]
&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;setItems&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; newItems: [Item]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items = newItems
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache.removeAll()
&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; precomputeHeights()
&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; tableView.reloadData()
&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;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;precomputeHeights&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; width = tableView.bounds.width
&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;for&lt;/span&gt; (index, item) &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; items.enumerated() {
&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; indexPath = IndexPath(row: index, section: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache[indexPath] = calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item, width: width)
&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;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateHeight&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; item: Item, width: CGFloat) -&amp;gt; CGFloat {
&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;let&lt;/span&gt; textHeight = item.content.boundingRect(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; with: CGSize(width: width &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;, height: .greatestFiniteMagnitude),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options: [.usesLineFragmentOrigin, .usesFontLeading],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attributes: [.font: UIFont.systemFont(ofSize: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &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; ).height
&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; ceil(textHeight) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&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&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, heightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&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; heightCache[indexPath] ?? UITableView.automaticDimension
&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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateItem&lt;/span&gt;(at indexPath: IndexPath, with item: Item) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items[indexPath.row] = item
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache[indexPath] = calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item, width: tableView.bounds.width)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadRows(at: [indexPath], with: .automatic)
&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="解决方案2使用estimatedheight"&gt;解决方案2：使用estimatedHeight&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EstimatedHeightTableViewController&lt;/span&gt;: UITableViewController {
&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; heightCache: [IndexPath: CGFloat] = [:]
&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&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; tableView.estimatedRowHeight = &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.rowHeight = UITableView.automaticDimension
&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
&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; heightCache[indexPath] = cell.bounds.height
&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;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&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;return&lt;/span&gt; heightCache[indexPath] ?? &lt;span style="color:#ae81ff"&gt;100&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="解决方案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-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果所有Cell高度相同，直接设置固定值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&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; tableView.rowHeight = &lt;span style="color:#ae81ff"&gt;80&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; tableView.estimatedRowHeight = &lt;span style="color:#ae81ff"&gt;0&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&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="基本原理"&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/stutter-%E4%B8%BB%E7%BA%BF%E7%A8%8B%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/stutter-%E4%B8%BB%E7%BA%BF%E7%A8%8B%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;主线程阻塞是卡顿最常见的原因。本文介绍如何优化主线程的工作，减少阻塞时间。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="主线程的职责"&gt;主线程的职责&lt;/h2&gt;
&lt;p&gt;主线程（UI线程）负责：&lt;/p&gt;
&lt;pre class="mermaid"&gt;mindmap
root((主线程职责))
事件处理
触摸事件
手势识别
UI更新
布局计算
视图绘制
动画执行
Core Animation
UIView动画
系统回调
生命周期
AppDelegate
定时器
NSTimer
CADisplayLink
通知处理
NotificationCenter
KVO
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;原则：主线程应该只做UI相关的轻量级工作&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="常见的主线程阻塞场景"&gt;常见的主线程阻塞场景&lt;/h2&gt;
&lt;h3 id="1-耗时计算"&gt;1. 耗时计算&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:#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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processData&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; result = heavyComputation(data) &lt;span style="color:#75715e"&gt;// 阻塞主线程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updateUI(with: result)
&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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processDataAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&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; result = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.heavyComputation(&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.data)
&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; 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;.updateUI(with: result)
&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="2-文件io"&gt;2. 文件I/O&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:#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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadConfig&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; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;? Data(contentsOf: configURL) &lt;span style="color:#75715e"&gt;// 阻塞&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parseConfig(data)
&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;// 优化后：异步I/O&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;loadConfigAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .utility).async {
&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; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;? Data(contentsOf: &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.configURL)
&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; 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;.parseConfig(data)
&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="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-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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsers&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; users = database.query(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM users&amp;#34;&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; tableView.reloadData()
&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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsersAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; database.queryAsync(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM users&amp;#34;&lt;/span&gt;) { [&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;] users &lt;span style="color:#66d9ef"&gt;in&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;?.users = users
&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;?.tableView.reloadData()
&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;hr&gt;
&lt;h2 id="任务异步化"&gt;任务异步化&lt;/h2&gt;
&lt;h3 id="基本原则"&gt;基本原则&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph main["主线程任务"]
direction LR
A1["UI更新&lt;br/&gt;视图刷新、动画"]
A2["用户交互&lt;br/&gt;点击响应、手势处理"]
A3["轻量计算&lt;br/&gt;简单数据转换"]
end
subgraph bg["后台线程任务"]
direction LR
B1["复杂计算&lt;br/&gt;数据处理、算法"]
B2["I/O操作&lt;br/&gt;文件读写、网络请求"]
B3["数据库操作&lt;br/&gt;查询、写入"]
B4["图片处理&lt;br/&gt;解码、缩放、滤镜"]
end
main --&gt; |"轻量、快速"| UI((用户界面))
bg --&gt; |"耗时、阻塞"| main
&lt;/pre&gt;
&lt;h3 id="gcd任务调度"&gt;GCD任务调度&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AsyncTaskManager&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;compute&lt;/span&gt;&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () -&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion: @escaping (T) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&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; result = work()
&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; completion(result)
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// I/O任务&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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion: @escaping (Result&amp;lt;T, Error&amp;gt;) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .utility).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&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; result = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; work()
&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; completion(.success(result))
&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;catch&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; completion(.failure(error))
&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&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;background&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .background).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; work()
&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&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;AsyncTaskManager.compute({
&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;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.processLargeDataSet()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}) { result &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 主线程更新UI&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;.displayResult(result)
&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="swift-concurrency"&gt;Swift Concurrency&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:#75715e"&gt;// 使用async/await&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;DataProcessor&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;processAsync&lt;/span&gt;() async &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; ProcessedData {
&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;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await Task.detached(priority: .userInitiated) {
&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;self&lt;/span&gt;.heavyProcessing()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.value
&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; @MainActor
&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;loadAndDisplay&lt;/span&gt;() async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&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; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await processAsync()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 自动在主线程更新UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updateUI(with: data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; showError(error)
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用TaskGroup并行处理&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;processImagesParallel&lt;/span&gt;(urls: [URL]) async -&amp;gt; [UIImage] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await withTaskGroup(of: UIImage?.&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;) { group &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; url &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; urls {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; group.addTask {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.loadImage(from: url)
&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;var&lt;/span&gt; images: [UIImage] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; await image &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; group {
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = image {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; images.append(image)
&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;return&lt;/span&gt; images
&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;hr&gt;
&lt;h2 id="任务拆分与调度"&gt;任务拆分与调度&lt;/h2&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/stutter-%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;理解卡顿的原理是优化的基础。本文从屏幕显示的底层机制出发，沿着&amp;quot;VSync信号 -&amp;gt; 渲染管线 -&amp;gt; RunLoop协作 -&amp;gt; 掉帧产生&amp;quot;的逻辑链条，逐步揭示卡顿产生的根本原因。&lt;/p&gt;
&lt;h2 id="屏幕显示的基础vsync与缓冲机制"&gt;屏幕显示的基础：VSync与缓冲机制&lt;/h2&gt;
&lt;p&gt;要理解卡顿，首先要理解屏幕是如何显示画面的。&lt;/p&gt;
&lt;h3 id="vsync信号"&gt;VSync信号&lt;/h3&gt;
&lt;p&gt;VSync（Vertical Synchronization，垂直同步）是显示器发出的信号，用于协调GPU渲染和屏幕显示的时机。在60Hz的屏幕上，每16.67ms发出一次VSync信号。当信号到来时，屏幕从帧缓冲区读取数据进行显示。&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;│←── 16.67ms ──→│←── 16.67ms ──→│←── 16.67ms ──→│
&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; VSync 1 VSync 2 VSync 3
&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; 显示帧1 显示帧2 显示帧3
&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;为了避免画面撕裂（GPU写入和屏幕读取同一块内存导致），iOS使用多缓冲机制：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 双缓冲机制
direction TB
GPU["GPU"] --&gt;|渲染到| BB["后缓冲区（Back Buffer）"]
BB &lt;--&gt;|VSync时交换| FB["前缓冲区（Frame Buffer）"]
FB --&gt;|读取显示| Display["显示器"]
end
&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双缓冲（默认）&lt;/strong&gt;：GPU渲染到后缓冲区，VSync到来时交换前后缓冲区，显示器从前缓冲区读取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;三缓冲（高负载时自动启用）&lt;/strong&gt;：增加第三个缓冲区，当渲染无法在一个VSync周期内完成时，GPU可以在额外缓冲区继续渲染，不必等待交换完成。代价是增加一帧延迟和内存占用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;系统在两者之间动态切换，开发者无需手动干预。&lt;/p&gt;
&lt;h3 id="promotion自适应刷新率"&gt;ProMotion自适应刷新率&lt;/h3&gt;
&lt;p&gt;ProMotion设备（iPhone 13 Pro及以上）支持10Hz-120Hz的自适应刷新率，这意味着帧时间预算不再固定：&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;120Hz&lt;/td&gt;
&lt;td&gt;8.33ms&lt;/td&gt;
&lt;td&gt;&amp;gt;16ms视为掉帧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;60Hz&lt;/td&gt;
&lt;td&gt;16.67ms&lt;/td&gt;
&lt;td&gt;&amp;gt;33ms视为掉帧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30Hz&lt;/td&gt;
&lt;td&gt;33.33ms&lt;/td&gt;
&lt;td&gt;&amp;gt;66ms视为掉帧&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-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;let&lt;/span&gt; maxFrameRate = UIScreen.main.maximumFramesPerSecond
&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;// CADisplayLink适配ProMotion&lt;/span&gt;
&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; &lt;span style="color:#75715e"&gt;#available&lt;/span&gt;(&lt;span style="color:#75715e"&gt;iOS&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15.0&lt;/span&gt;, &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; displayLink?.preferredFrameRateRange = CAFrameRateRange(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimum: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; maximum: &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; preferred: &lt;span style="color:#ae81ff"&gt;120&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;h2 id="ios渲染架构"&gt;iOS渲染架构&lt;/h2&gt;
&lt;p&gt;了解了屏幕显示机制后，接下来看iOS是如何将UI元素最终变成屏幕上的像素的。&lt;/p&gt;</description></item><item><title>卡顿-图片优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%9B%BE%E7%89%87%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/stutter-%E5%9B%BE%E7%89%87%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;图片处理是iOS应用中常见的性能瓶颈。本文介绍图片解码原理以及各种优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="图片解码原理"&gt;图片解码原理&lt;/h2&gt;
&lt;h3 id="为什么需要解码"&gt;为什么需要解码&lt;/h3&gt;
&lt;p&gt;图片文件（PNG、JPEG等）是压缩格式，无法直接显示。GPU需要的是位图（Bitmap）格式：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A[压缩图片&lt;br/&gt;PNG/JPEG] --&gt; B[解码&lt;br/&gt;Decode&lt;br/&gt;CPU密集操作]
B --&gt; C[位图&lt;br/&gt;Bitmap&lt;br/&gt;GPU可直接使用]
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;位图大小 = 宽度 × 高度 × 每像素字节数
例如：1000×1000 RGBA图片 = 1000 × 1000 × 4 = 4MB&lt;/p&gt;
&lt;/blockquote&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:#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;let&lt;/span&gt; image = UIImage(named: &lt;span style="color:#e6db74"&gt;&amp;#34;large_image&amp;#34;&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;// 设置到ImageView（仍未解码）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;imageView.image = image
&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;// 在 CATransaction commit 的 prepare 阶段，Core Animation 会在主线程对未解码的图片执行解码&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异步解码"&gt;异步解码&lt;/h2&gt;
&lt;h3 id="基本原理"&gt;基本原理&lt;/h3&gt;
&lt;p&gt;将解码工作移到后台线程：&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
participant M as 主线程
participant B as 后台线程
M-&gt;&gt;B: 请求加载图片
Note over M: 继续处理其他事件
B-&gt;&gt;B: 加载压缩数据
B-&gt;&gt;B: 解码为位图
B-&gt;&gt;B: 创建CGImage
B-&gt;&gt;M: 返回解码后的图片
M-&gt;&gt;M: 更新UI
&lt;/pre&gt;
&lt;h3 id="实现方案1强制解码"&gt;实现方案1：强制解码&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;extension&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UIImage&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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodedImage&lt;/span&gt;() -&amp;gt; UIImage? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cgImage = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.cgImage &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &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;
&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; width = cgImage.width
&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; height = cgImage.height
&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;let&lt;/span&gt; colorSpace = CGColorSpaceCreateDeviceRGB()
&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; bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue &lt;span style="color:#f92672"&gt;|&lt;/span&gt; CGBitmapInfo.byteOrder32Little.rawValue)
&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;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; context = CGContext(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: &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; width: width,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: height,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bitsPerComponent: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bytesPerRow: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; space: colorSpace,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bitmapInfo: bitmapInfo.rawValue
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) &lt;span style="color:#66d9ef"&gt;else&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;nil&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; context.draw(cgImage, &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;: CGRect(x: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, y: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, width: width, height: height))
&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;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; decodedCGImage = context.makeImage() &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &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;
&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; UIImage(cgImage: decodedCGImage, scale: scale, orientation: imageOrientation)
&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:#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;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadImageAsync&lt;/span&gt;(named name: String, completion: @escaping (UIImage?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&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; image = UIImage(named: name)?.decodedImage()
&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; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(image)
&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="实现方案2使用imageio"&gt;实现方案2：使用ImageIO&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;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageIO&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;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageDecoder&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodeImage&lt;/span&gt;(from url: URL) -&amp;gt; UIImage? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; source = CGImageSourceCreateWithURL(url &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; CFURL, &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;else&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;nil&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;let&lt;/span&gt; options: [CFString: Any] = [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kCGImageSourceShouldCache: &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; kCGImageSourceShouldCacheImmediately: &lt;span style="color:#66d9ef"&gt;true&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&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;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cgImage = CGImageSourceCreateImageAtIndex(source, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, options &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; CFDictionary) &lt;span style="color:#66d9ef"&gt;else&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;nil&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;return&lt;/span&gt; UIImage(cgImage: cgImage)
&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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodeImageAsync&lt;/span&gt;(from url: URL, completion: @escaping (UIImage?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&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; image = ImageDecoder.decodeImage(from: url)
&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; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(image)
&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="实现方案3使用uigraphicsimagerenderer"&gt;实现方案3：使用UIGraphicsImageRenderer&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;extension&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UIImage&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;decodedImageUsingRenderer&lt;/span&gt;() -&amp;gt; UIImage {
&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; format = UIGraphicsImageRendererFormat()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format.scale = scale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format.opaque = &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; format.preferredRange = .standard
&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; renderer = UIGraphicsImageRenderer(size: size, format: format)
&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; renderer.image { context &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; draw(at: .zero)
&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;hr&gt;
&lt;h2 id="图片降采样"&gt;图片降采样&lt;/h2&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/stutter-%E6%A3%80%E6%B5%8B/</link><pubDate>Thu, 07 May 2026 16:54:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E6%A3%80%E6%B5%8B/</guid><description>&lt;p&gt;准确检测卡顿是优化的前提。本文介绍多种卡顿检测方案，从开发调试到线上监控都有对应的方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="检测方案概览"&gt;检测方案概览&lt;/h2&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;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CADisplayLink&lt;/td&gt;
&lt;td&gt;监控帧节奏、FPS、慢帧/掉帧&lt;/td&gt;
&lt;td&gt;简单直接、适合趋势观察&lt;/td&gt;
&lt;td&gt;无法直接给出堆栈，FPS 只能辅助判断&lt;/td&gt;
&lt;td&gt;开发调试/线上辅助指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RunLoop Observer&lt;/td&gt;
&lt;td&gt;监控RunLoop状态&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;子线程Ping&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;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruments&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;/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;iOS 13+&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentry ANR V2&lt;/td&gt;
&lt;td&gt;帧延迟分析&lt;/td&gt;
&lt;td&gt;区分阻塞类型&lt;/td&gt;
&lt;td&gt;需集成SDK&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="1-cadisplaylink监控"&gt;1. CADisplayLink监控&lt;/h2&gt;
&lt;h3 id="基本原理"&gt;基本原理&lt;/h3&gt;
&lt;p&gt;CADisplayLink 是一个和屏幕显示刷新节奏同步的回调。它适合回答“当前 UI 刷新是否顺畅、是否出现慢帧、掉帧或冻结帧”，但 &lt;strong&gt;FPS 本身只是辅助参考&lt;/strong&gt;，不能单独作为卡顿结论。&lt;/p&gt;
&lt;p&gt;原因是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;FPS 只描述结果，不描述原因&lt;/strong&gt;：FPS 下降只能说明某段时间显示帧变少了，不能告诉你是主线程计算、布局、图片解码、锁等待、I/O、GPU 渲染还是系统主动降刷新率导致的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ProMotion 会动态调整刷新率&lt;/strong&gt;：在支持 120Hz 的机型上，系统可能根据内容和功耗策略把刷新率降到 10Hz、24Hz、30Hz、60Hz、80Hz、120Hz 等。静止页面低 FPS 可能只是系统主动省电，不是卡顿。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主线程阻塞会让回调延迟&lt;/strong&gt;：如果主线程真的被阻塞，CADisplayLink 回调本身也会延后，此时需要结合实际回调间隔、RunLoop 状态和堆栈采样判断。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此线上卡顿监控更推荐记录 &lt;strong&gt;帧间隔 / 慢帧 / 冻结帧 / 交互场景&lt;/strong&gt;，而不是只显示一个“当前 FPS”。&lt;/p&gt;</description></item><item><title>卡顿-离屏渲染</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93/</guid><description>&lt;p&gt;离屏渲染（Offscreen Rendering）是GPU渲染中的性能杀手。本文介绍离屏渲染的原理、触发条件以及优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什么是离屏渲染"&gt;什么是离屏渲染&lt;/h2&gt;
&lt;h3 id="正常渲染流程"&gt;正常渲染流程&lt;/h3&gt;
&lt;p&gt;正常情况下，GPU直接将渲染结果写入帧缓冲区（Frame Buffer）：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 正常渲染["正常渲染 On-Screen Rendering"]
A[GPU&lt;br/&gt;渲染] --&gt; B[Frame Buffer&lt;br/&gt;帧缓冲区] --&gt; C[屏幕&lt;br/&gt;显示]
end
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接渲染到帧缓冲区&lt;/li&gt;
&lt;li&gt;渲染完成即可显示&lt;/li&gt;
&lt;li&gt;效率最高&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="离屏渲染流程"&gt;离屏渲染流程&lt;/h3&gt;
&lt;p&gt;离屏渲染需要先渲染到离屏缓冲区，再合成到帧缓冲区：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 离屏渲染["离屏渲染 Offscreen Rendering"]
A[GPU&lt;br/&gt;渲染] --&gt; B[Offscreen Buffer&lt;br/&gt;离屏缓冲区]
B --&gt; C[Frame Buffer&lt;br/&gt;帧缓冲区]
C --&gt; D[屏幕&lt;br/&gt;显示]
end
E[额外的缓冲区] -.-&gt; B
style A fill:#e1f5fe
style B fill:#f48fb1
style C fill:#fff3e0
style D fill:#e8f5e9
style E fill:#f48fb1,stroke:#f44336,stroke-dasharray: 5 5
&lt;/pre&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/stutter-%E5%8D%A1%E9%A1%BF/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8D%A1%E9%A1%BF/</guid><description>&lt;p&gt;卡顿是影响用户体验的关键问题之一。当应用无法在一帧的时间内（通常为16.67ms）完成渲染工作时，就会出现掉帧，用户会感知到界面不流畅。&lt;/p&gt;
&lt;p&gt;本系列文章从渲染原理入手，系统性地介绍iOS卡顿的检测与优化方法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;卡顿监控是 APM 流畅性子系的核心能力，线上指标体系、检测采集、上报策略请参考 &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;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/"&gt;业界方案（微信 Matrix / 字节 Slardar 卡死监控）&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="什么是卡顿"&gt;什么是卡顿&lt;/h2&gt;
&lt;p&gt;iOS设备的屏幕刷新率通常为60Hz（ProMotion设备可达120Hz），这意味着每秒需要渲染60帧画面。每一帧的渲染时间窗口约为16.67ms（1000ms / 60）。&lt;/p&gt;
&lt;p&gt;当CPU或GPU无法在这个时间窗口内完成工作时，就会发生掉帧（Frame Drop），用户会感知到卡顿。&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;偶尔掉1-2帧&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;长时间阻塞（&amp;gt;250ms）&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;p&gt;iOS的渲染流程涉及CPU和GPU的协作，通过Core Animation Pipeline完成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph APP["App 进程（CPU 阶段）"]
direction TB
Layout["Layout（布局计算）&lt;br/&gt;layoutSubviews、约束计算"]
Display["Display（绘制显示）&lt;br/&gt;drawRect:、文本绘制"]
Prepare["Prepare（准备）&lt;br/&gt;图片解码、格式转换"]
Commit["Commit（提交）&lt;br/&gt;打包图层树"]
Layout --&gt; Display --&gt; Prepare --&gt; Commit
end
subgraph RS["Render Server 进程（GPU 阶段）"]
direction TB
Decode["解码图层树"]
Vertex["顶点着色器"]
Raster["光栅化"]
Fragment["片段着色器"]
Buffer["帧缓冲区写入"]
Decode --&gt; Vertex --&gt; Raster --&gt; Fragment --&gt; Buffer
end
APP --&gt;|"IPC 传输"| RS
RS --&gt; VSync["VSync 信号到来"]
VSync --&gt; Screen["显示到屏幕"]
&lt;/pre&gt;
&lt;h3 id="cpu与gpu的职责"&gt;CPU与GPU的职责&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;CPU&lt;/td&gt;
&lt;td&gt;布局计算、视图创建、文本计算、图片解码&lt;/td&gt;
&lt;td&gt;复杂布局、大量文本、主线程阻塞&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU&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="cpu瓶颈"&gt;CPU瓶颈&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;主线程阻塞&lt;/strong&gt;：耗时操作在主线程执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂布局&lt;/strong&gt;：大量约束计算、频繁布局&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文本计算&lt;/strong&gt;：复杂富文本、大量文本渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图片解码&lt;/strong&gt;：大图片在主线程解码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对象创建&lt;/strong&gt;：大量对象的创建和销毁&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="gpu瓶颈"&gt;GPU瓶颈&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;离屏渲染&lt;/strong&gt;：圆角、阴影、遮罩触发离屏渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图层混合&lt;/strong&gt;：大量透明图层叠加&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超大图片&lt;/strong&gt;：纹理尺寸超过GPU限制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂特效&lt;/strong&gt;：模糊、滤镜等GPU密集操作&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item><item><title>包瘦身-App Thinning</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-appthinning/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-appthinning/</guid><description>&lt;p&gt;App Thinning是Apple提供的包体积优化技术，让用户只下载适合其设备的内容。本文详细介绍App Thinning的三个组成部分及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="整体架构"&gt;整体架构&lt;/h2&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-fallback" data-lang="fallback"&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;│ Universal IPA │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── arm64 代码 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── @1x/@2x/@3x 图片 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── iPhone/iPad 资源 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Metal GPU资源（OpenGL ES已弃用） │
&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; App Store处理
&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;│ iPhone 12 │ │ iPhone 8 │ │ iPad Pro │
&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;│ @3x图片 │ │ @2x图片 │ │ @2x图片 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ arm64 │ │ arm64 │ │ arm64 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ A14 GPU │ │ A11 GPU │ │ M1 GPU │
&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;App Thinning包含三个部分：&lt;/p&gt;</description></item><item><title>包瘦身-分析工具</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7/</guid><description>&lt;p&gt;在进行包体积优化之前，首先需要了解如何分析包体积。本文介绍常用的分析工具和Mach-O文件结构。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="查看ipa构成"&gt;查看IPA构成&lt;/h2&gt;
&lt;p&gt;解压IPA文件分析各部分大小：&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 解压IPA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unzip -q YourApp.ipa -d ./ipa_content
&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;find ./ipa_content -type f -exec ls -lh &lt;span style="color:#f92672"&gt;{}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\;&lt;/span&gt; | sort -k5 -h -r | head -20
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="linkmap分析"&gt;LinkMap分析&lt;/h2&gt;
&lt;p&gt;LinkMap文件记录了链接器生成可执行文件的详细信息，可以精确分析二进制大小：&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Build Settings中设置
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write Link Map File = YES
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Path to Link Map File = $(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="linkmap文件结构"&gt;LinkMap文件结构&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Path: /path/to/YourApp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Arch: arm64
&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;# Object files:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 0] linker synthesized
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 1] /path/to/ViewController.o
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 2] /path/to/Model.o
&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;# Sections:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Address Size Segment Section
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001000 0x00012345 __TEXT __text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100013345 0x00001234 __TEXT __stubs
&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;# Symbols:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Address Size File Name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001000 0x00000100 [ 1] -[ViewController viewDidLoad]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001100 0x00000050 [ 2] -[Model init]
&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;可以使用脚本解析LinkMap统计各模块大小：&lt;/p&gt;</description></item><item><title>包瘦身-可执行文件优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%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/size-%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;可执行文件通常占iOS应用包体积的30-50%，是优化的重点。本文介绍各种可执行文件优化手段及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="编译器优化选项"&gt;编译器优化选项&lt;/h2&gt;
&lt;h3 id="优化级别原理"&gt;优化级别原理&lt;/h3&gt;
&lt;p&gt;编译器优化级别控制了LLVM在编译时应用的优化Pass数量和类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是优化Pass？&lt;/strong&gt; Pass是指编译器对代码进行的一次特定优化处理过程。LLVM将优化工作分解为多个独立的Pass，每个Pass负责一种特定类型的优化：&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;源代码 → 前端解析 → IR（中间表示）→ Pass1 → Pass2 → Pass3 → ... → 优化后的代码 → 机器码
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;常见的优化Pass包括：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pass名称&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dead Code Elimination&lt;/td&gt;
&lt;td&gt;删除永远不会执行的代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant Folding&lt;/td&gt;
&lt;td&gt;编译时计算常量表达式，如&lt;code&gt;3+5&lt;/code&gt;直接变成&lt;code&gt;8&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function Inlining&lt;/td&gt;
&lt;td&gt;将函数调用替换为函数体本身&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop Unrolling&lt;/td&gt;
&lt;td&gt;展开循环，减少循环控制开销&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common Subexpression Elimination&lt;/td&gt;
&lt;td&gt;消除重复计算的表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不同的优化级别启用不同数量和类型的Pass：&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Build Settings
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Optimization Level = -Os # 级别：-Os 优化大小（推荐用于Release）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;-O0（无优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不应用任何优化Pass，编译速度最快。代码按原样生成，保留所有变量和控制流，便于调试。适用于Debug构建。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-O1（基础优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;应用不显著增加编译时间的基础优化，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本的死代码消除&lt;/li&gt;
&lt;li&gt;简单的常量折叠&lt;/li&gt;
&lt;li&gt;基本块合并&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;死代码消除：&lt;/strong&gt; 死代码消除（Dead Code Elimination）是指编译器自动移除永远不会被执行或执行结果不会被使用的代码。注意：这里的死代码消除是编译阶段的优化，作用于函数内部；而后文提到的Dead Code Stripping是链接阶段的优化，用于移除未被引用的整个函数或类。&lt;/p&gt;
&lt;p&gt;-O1 适合需要一定优化但对编译速度敏感的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-O2（标准优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;应用大多数优化Pass，是性能和体积的平衡点。包括：&lt;/p&gt;</description></item><item><title>包瘦身-资源优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E8%B5%84%E6%BA%90%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/size-%E8%B5%84%E6%BA%90%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;资源文件通常占iOS应用包体积的40-60%，是优化的重要方向。本文介绍各种资源优化手段及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="图片优化"&gt;图片优化&lt;/h2&gt;
&lt;h3 id="asset-catalog原理"&gt;Asset Catalog原理&lt;/h3&gt;
&lt;p&gt;Asset Catalog（&lt;code&gt;.xcassets&lt;/code&gt;）编译后生成&lt;code&gt;Assets.car&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-fallback" data-lang="fallback"&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;Images.xcassets/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── AppIcon.appiconset/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── icon-60@2x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── icon-60@3x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Logo.imageset/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── logo@2x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── logo@3x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── Contents.json
&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;Assets.car ← 单一文件，包含所有资源
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Assets.car的优化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图片被重新编码，使用更高效的压缩&lt;/li&gt;
&lt;li&gt;支持App Thinning，按设备分发&lt;/li&gt;
&lt;li&gt;运行时高效加载（内存映射）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以使用&lt;code&gt;assetutil&lt;/code&gt;查看Assets.car内容：&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assetutil --info Assets.car
&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;strong&gt;PNG压缩原理&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;PNG使用DEFLATE无损压缩，但可以通过以下方式减小体积：&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;原始PNG结构：
&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;│ PNG Header │
&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;│ IHDR (图像信息) │
&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;│ IDAT (图像数据) │ ← 压缩的像素数据
&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;│ 辅助chunks │ ← 可以移除
&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;1. 移除不必要的chunks（如tEXt、iTXt）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 优化DEFLATE压缩参数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 减少颜色数量（有损）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 使用更高效的滤波器
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;有损压缩原理（pngquant）&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>包瘦身</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8C%85%E7%98%A6%E8%BA%AB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8C%85%E7%98%A6%E8%BA%AB/</guid><description>&lt;p&gt;包体积（IPA大小）是iOS应用的重要质量指标。App Store对蜂窝网络下载有200MB的提示阈值，超过这个大小会弹窗询问用户是否使用流量下载（iOS 13之前是强制要求Wi-Fi）。这个弹窗会增加用户的决策成本，影响下载转化率。因此，包体积优化对于用户获取和留存都有重要影响。&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.app&lt;/td&gt;
&lt;td&gt;目录&lt;/td&gt;
&lt;td&gt;应用程序包，是一个包含可执行文件和资源的目录结构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.xcarchive&lt;/td&gt;
&lt;td&gt;目录&lt;/td&gt;
&lt;td&gt;Xcode归档包，包含.app、dSYM符号文件、构建信息等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.ipa&lt;/td&gt;
&lt;td&gt;文件&lt;/td&gt;
&lt;td&gt;安装包，本质是ZIP压缩的.app，用于分发和安装&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;：Xcode直接将&lt;code&gt;.app&lt;/code&gt;安装到模拟器或真机&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试分发&lt;/strong&gt;：使用&lt;code&gt;.ipa&lt;/code&gt;通过TestFlight、蒲公英、fir.im等平台分发给测试人员&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App Store上架&lt;/strong&gt;：通过Xcode或Transporter将&lt;code&gt;.xcarchive&lt;/code&gt;导出并上传到App Store Connect（实际上传的是从xcarchive导出的IPA或直接上传xcarchive中的内容）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="appapplication-bundle"&gt;.app（Application Bundle）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.app&lt;/code&gt;是macOS/iOS应用的标准格式，实际上是一个目录（Finder中显示为单个文件）。包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可执行文件（Mach-O格式）&lt;/li&gt;
&lt;li&gt;Info.plist配置文件&lt;/li&gt;
&lt;li&gt;资源文件（图片、音频、本地化文件等）&lt;/li&gt;
&lt;li&gt;Frameworks目录（动态库）&lt;/li&gt;
&lt;li&gt;PlugIns目录（App Extension）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="xcarchivexcode-archive"&gt;.xcarchive（Xcode Archive）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.xcarchive&lt;/code&gt;是Xcode的归档格式，用于保存完整的构建产物。目录结构：&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;YourApp.xcarchive/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Products/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Applications/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── YourApp.app # 应用程序包
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── dSYMs/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── YourApp.app.dSYM # 符号文件（用于崩溃解析）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Info.plist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── SCMBlueprint/ # 源码管理信息
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主要用途：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保存dSYM符号文件，用于线上崩溃日志符号化&lt;/li&gt;
&lt;li&gt;导出不同分发渠道的IPA（App Store、Ad Hoc、Enterprise）&lt;/li&gt;
&lt;li&gt;上传到App Store Connect&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ipaios-app-store-package"&gt;.ipa（iOS App Store Package）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.ipa&lt;/code&gt;是iOS应用的安装包格式，本质是一个ZIP压缩文件。结构：&lt;/p&gt;</description></item></channel></rss>