WWDC Quick Look 💓 By SwiftGGTeam
Track down hangs with Xcode and on-device detection

Track down hangs with Xcode and on-device detection

观看原视频

Highlight

性能工具团队的 John Crowson 以一个甜甜圈食品卡车管理应用为例,系统介绍了在不同开发阶段追踪卡顿的工具。卡顿(Hang)被定义为主线程忙碌或等待其他线程/系统资源超过 250 毫秒,导致视图无法更新的时间段。


核心内容

开发阶段最容易看到卡顿。你在 Xcode 里运行 App,滑动列表,界面停住了几百毫秒。问题看得见,却未必知道原因。

发布之后更麻烦。用户手里的设备、网络和系统版本都不同。桌面上复现不了的卡顿,可能正好发生在弱网、旧设备或某个冷门路径里。

这场 session 把卡顿诊断拆成三个阶段:开发时、Beta 测试时、发布后。Apple 在 iOS 16 和 Xcode 14 加了几类工具,让每个阶段都有对应的信号来源。

第一个阶段用 Xcode。Thread Performance Checker 在调试时提醒优先级反转和主线程非 UI 工作。Instruments 的 Time Profiler 会在时间线上直接标出 hang。

第二个阶段用设备端检测。开发签名 App 或 TestFlight App 可以在 Settings > Developer > Hang Detection 打开检测。设备会在发生 hang 时给出通知,之后生成文本 hang log 和 tailspin。

第三个阶段用 Xcode Organizer。发布后,Organizer 的 Hang Reports 会把用户设备上收集到的主线程堆栈按 signature 分组,并按用户影响排序。

这条链路的目标很明确:越早发现,成本越低;越接近真实用户,数据越能说明影响范围。

详细内容

1. 先定义什么是 hang

01:20)Apple 对 hang 的定义很具体:主线程正在工作,或正在等待其他线程、系统资源,导致视图内容至少 250 毫秒无法更新。

主线程还负责处理用户交互。它被占住时,新的触摸事件也要等待。用户看到的效果就是 App 卡住。

这场演讲里的 Food Truck App 在滚动甜甜圈列表时停顿。这个例子对应两类常见原因:主线程等待低优先级 worker 线程,或主线程执行同步网络、磁盘操作。

概念示例:hang 判定

Main thread is busy or waiting
View update is delayed >= 250 ms
New user interactions wait until the main thread is available
Result: the app appears stuck

关键点:

  • Main thread is busy or waiting:来源是 transcript 对 hang 的定义,主线程可能自己在工作,也可能在等别的线程或系统资源。
  • View update is delayed >= 250 ms:250 毫秒是本场 session 明确给出的报告阈值。
  • New user interactions wait:主线程不可用时,新的用户交互也无法及时处理。
  • Result:这不是崩溃,进程还活着;用户感受到的是界面停住。

2. 开发阶段:Thread Performance Checker 先报警

04:43)Xcode 14 的 Thread Performance Checker 会在 Issue Navigator 里提示两类 hang 风险:优先级反转,以及主线程上的非 UI 工作。

演讲中的 Food Truck App 触发了优先级反转提示。高优先级线程正在等待低优先级线程。主线程如果在这条等待链上,滚动就会停住。

开启位置也很具体:在 scheme 的 Diagnostics 区域启用 Thread Performance Checker。

概念示例:开发阶段检查

Scheme > Diagnostics
Enable Thread Performance Checker
Run the app in Xcode
Repeat the slow interaction
Inspect the Issue Navigator warning

关键点:

  • Scheme > Diagnostics:演讲说明该工具从 scheme 的 Diagnostics 区域开启。
  • Enable Thread Performance Checker:这是 Xcode 14 新增的开发阶段检查入口。
  • Run the app in Xcode:它适合连接 Xcode 调试时使用,不需要主动录制 trace。
  • Repeat the slow interaction:工具通过真实交互暴露风险,Food Truck 的例子是滚动甜甜圈列表。
  • Inspect the Issue Navigator warning:报警会指出优先级反转或主线程非 UI 工作这类风险。

这个工具的价值是快。它不能替你完整解释 worker 线程在做什么,但能把调查方向从“界面慢”缩小到“线程等待关系有问题”。

3. 开发阶段:Time Profiler 把 hang 标到时间线上

05:56)下一步是 Instruments。Time Profiler 能展示每个线程随时间变化的 call stack。Xcode 14 里,它还会检测 hang,并在对应进程轨道上打标签。

演讲里的调查步骤是:从 Xcode 的 Product > Profile 进入 Instruments,选择 Time Profiler,录制有问题的滚动操作。时间线上出现 hang 标签后,三击 hang 区间,把底部详情过滤到这段时间。

过滤后,John Crowson 先看主线程 CPU。主线程几乎没有 CPU 使用,说明它处在等待状态。再看其他轨道,一个 worker 线程在 hang 期间 CPU 很高。这个 worker 线程就是下一步要检查的对象。

概念示例:Time Profiler 调查路径

Product > Profile
Choose Time Profiler
Record the problematic interaction
Triple-click the hang interval
Compare main thread CPU with worker thread CPU
Open call stacks in the filtered time range

关键点:

  • Product > Profile:演讲通过 Xcode 这个菜单进入 Instruments,并用 release 构建启动 App。
  • Choose Time Profiler:Time Profiler 提供线程随时间变化的调用栈。
  • Record the problematic interaction:录制范围要覆盖可复现的用户操作。
  • Triple-click the hang interval:三击 hang 区间会创建时间过滤器,只看 hang 期间的事件。
  • Compare main thread CPU with worker thread CPU:主线程 CPU 很低时,重点转向等待关系;worker 线程 CPU 很高时,检查它在 hang 期间的调用栈。
  • Open call stacks:最终要回到具体函数,而不是停留在“发生了 hang”这个结论。

08:00)Time Profiler 和 CPU Profiler 默认支持 hang 检测。Xcode 14 还提供独立的 hang tracing instrument,可以加到任意 trace document 里,并配置 hang duration threshold。

4. Beta 阶段:设备端 hang detection 覆盖真实环境

09:08)桌面调试有一个盲区:环境太理想。Food Truck App 在 Xcode 和稳定网络下没有明显问题,到了外面卖甜甜圈、网络变差时,打开订单页面卡了三秒以上。

iOS 16 的 on-device hang detection 用来覆盖这段空白。它在设备端工作,不要求连接 Xcode,也不要求正在录制 Instruments trace。适用对象是开发签名 App 或 TestFlight App。

开启路径是 Settings > Developer > Hang Detection。Hang Threshold 可以设置最短检测时长,最低 250 毫秒,也可以提高到 500 毫秒或更高。

概念示例:设备端检测配置

Settings > Developer > Hang Detection
Turn on Hang Detection
Set Hang Threshold to 250 ms or higher
Install a development-signed or TestFlight build
Use the app in real-world conditions
Wait for hang notifications and diagnostics

关键点:

  • Settings > Developer > Hang Detection:这是演讲给出的系统设置路径。
  • Turn on Hang Detection:打开后,设备可以在无 Xcode 连接时监测 hang。
  • Set Hang Threshold:阈值最低 250 毫秒;更高阈值适合优先抓用户影响更大的长卡顿。
  • development-signed or TestFlight build:session 明确限定了支持范围。
  • real-world conditions:Food Truck 的例子强调弱网等真实条件。
  • notifications and diagnostics:工具会发出实时通知,并在之后提供诊断材料。

10:30)这些诊断是 best-effort。系统会以低优先级在后台处理,减少性能开销。设备忙时,诊断生成会更慢。新的诊断可用时,会出现被动通知。

5. Beta 阶段:用 hang log 和 tailspin 找到同步调用

10:58)设备端检测会提供两类材料:文本 hang log 和 tailspin。

文本 hang log 信息少,但适合快速扫一眼。tailspin 可以在 Instruments 里打开,用来观察进程内线程交互,或查看系统资源使用。

演讲中的文本 hang log 显示:hang 期间主线程调用了一个会同步请求网络的方法。桌面上的强网络掩盖了问题;弱网下,同步请求变慢,主线程被拖住。

概念示例:从设备端诊断到修复方向

Receive an on-device hang notification
Open the generated hang log
Symbolicate the log on a Mac
Find the main thread stack during the hang
Look for synchronous network or disk work
Move that work off the main thread

关键点:

  • Receive an on-device hang notification:检测入口来自真实设备上的通知。
  • Open the generated hang log:文本日志可先给出主线程在 hang 时的堆栈线索。
  • Symbolicate the log on a Mac:演讲中把日志 share 到 Mac 后进行符号化,便于阅读函数名。
  • Find the main thread stack:本场 session 的诊断关注主线程为什么无法更新视图。
  • synchronous network or disk work:同步网络请求和同步磁盘读取都是演讲里的具体例子。
  • Move that work off the main thread:修复方向来自堆栈事实,而不是猜测。

6. 发布后:Organizer 用聚合报告排序用户影响

12:35)App 发布后,Xcode 14 的 Organizer 支持 Hang Reports。数据来自同意分享 App Analytics 的用户设备,内容包含导致 hang 的主线程 stack trace。

相似 stack trace 会被归为同一个 signature。列表按用户影响排序。每个 signature 里可以看样本 hang log、主线程堆栈、hang 时长、设备和 OS 版本。它还会显示该 signature 负责多少 hang log,并按 OS 版本和设备拆分。

演讲中的 top signature 占这个版本 21% 的 hang time。因为提交 App Store 时带了 symbol information,Organizer 能展示源代码里的函数名。John Crowson 通过主线程调用栈判断,这个 hang 来自主线程同步读磁盘文件。

概念示例:发布后排查顺序

Open Xcode Organizer
Select Hang Reports
Sort signatures by user impact
Open the top signature
Inspect sample hang logs and main thread stack traces
Check OS and device breakdowns
Fix the source code path with the largest impact

关键点:

  • Open Xcode Organizer:发布后的入口在 Organizer。
  • Select Hang Reports:Xcode 14 新增了 hang reports 支持。
  • Sort signatures by user impact:演讲建议优先处理最影响客户的 top signatures。
  • Open the top signature:signature 是相似 stack trace 的分组。
  • sample hang logs and main thread stack traces:样本日志用于定位具体代码路径。
  • OS and device breakdowns:拆分信息帮助判断问题是否集中在特定系统或设备。
  • largest impact:修复顺序由真实用户影响决定。

15:21)为了让 Organizer 报告可读,Apple 建议提交 App Store 时附带 symbol information。它会让报告展示函数名,并支持从 stack trace 的函数一键跳到 Xcode 源码。提取的信息限于函数和方法名、源码路径、行号,并会安全存储,不会共享。

核心启发

1. 给每个新功能加一次“主线程体检”

  • 做什么:新页面合入前,用 Thread Performance Checker 和 Time Profiler 跑一次核心交互。
  • 为什么值得做:session 强调开发阶段就能发现优先级反转和主线程非 UI 工作,越早修成本越低。
  • 怎么开始:在 scheme 的 Diagnostics 里打开 Thread Performance Checker;对列表滚动、页面打开、搜索输入这类高频操作录制 Time Profiler。

2. 把弱网测试变成 Beta 清单的一项

  • 做什么:TestFlight 测试时,在弱网或网络切换场景打开订单、详情、搜索和同步页面。
  • 为什么值得做:Food Truck 示例里的同步网络请求在桌面强网络下不明显,到了真实环境才触发三秒以上 hang。
  • 怎么开始:在测试设备的 Settings > Developer > Hang Detection 打开检测,把阈值先设为 250ms 或 500ms,收集通知后的 hang log。

3. 为发布后问题建立 top signature 处理节奏

  • 做什么:每次发版后检查 Xcode Organizer 的 Hang Reports,先处理占 hang time 比例最高的 signature。
  • 为什么值得做:Organizer 会按用户影响排序,演讲中的 top signature 占该版本 21% hang time。
  • 怎么开始:发布后固定查看 Hang Reports;打开 top signature,读取样本 hang log、设备和 OS 拆分,再回到对应源码路径修复。

4. 把 symbol information 当作性能诊断的一部分

  • 做什么:提交 App Store 时保留 symbol information。
  • 为什么值得做:Organizer 需要它把报告里的栈帧还原成函数名,并支持跳转到 Xcode 源码。
  • 怎么开始:检查归档和上传流程,确认符号信息随 App 提交;发版后用 Organizer 验证 hang report 能显示函数名。

5. 为同步 I/O 和同步网络建立代码审查规则

  • 做什么:代码审查时标记主线程上的同步网络请求、同步磁盘读取和可能导致等待的线程同步。
  • 为什么值得做:session 的两个具体案例分别来自同步网络请求和主线程同步读磁盘文件。
  • 怎么开始:把“主线程是否等待网络、磁盘、低优先级线程”加入 review checklist;有疑问时用 Instruments 的 hang 区间过滤验证。

关联 Session

评论

GitHub Issues · utterances