关于 performance-profiling
面向 Apple 平台应用开发者的性能分析指南,涵盖 Instruments、Xcode 诊断和 MetricKit。按响应、内存、启动与能耗问题提供分析流程和修复建议。
主要功能
- 01分析 CPU、内存、启动与能耗
- 02按性能问题选择分析工具
- 03提供逐步分析流程和修复模式
- 04使用 MetricKit 监控线上表现
- 05列出性能审查清单
适用场景
- 01排查界面卡顿和丢帧
- 02定位内存泄漏或内存增长
- 03优化应用启动时间
- 04诊断耗电和热量问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ rshankras/ claude-code-apple-skills --skill performance-profiling安装后在 Claude Code 中输入/performance-profiling确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
energy-diagnostics.mdhitches.mdlaunch-optimization.mdmemory-profiling.mdtime-profiler.md详细介绍
性能分析
使用 Instruments、Xcode 诊断工具和 MetricKit 分析 Apple 平台应用的系统指南。涵盖 CPU、内存、启动时间和能耗分析,并提供可操作的修复模式。
此技能的触发条件
在以下情况下使用此技能:
- 用户报告应用卡住、卡顿或丢帧
- 需要分析 CPU 使用情况或找出热点代码路径
- 存在内存泄漏、内存使用量过高或 OOM 崩溃
- 想要优化应用启动时间
- 需要降低电池/能耗影响
- 询问 Instruments、Time Profiler、Allocations 或 Leaks
- 想要在代码中添加
os_signpost或性能测量 - 正在准备 App Store 审核,需要验证性能
决策树
What performance problem are you investigating?
│
├─ App hangs / unresponsive to taps / slow UI
│ └─ Read time-profiler.md
│
├─ Scroll or animation stutter / dropped frames / hitches
│ └─ Read hitches.md
│
├─ High memory / leaks / OOM crashes / growing footprint
│ └─ Read memory-profiling.md
│
├─ Slow app launch / time to first frame
│ └─ Read launch-optimization.md
│
├─ Battery drain / thermal throttling / background energy
│ └─ Read energy-diagnostics.md
│
├─ General "app feels slow" (unknown cause)
│ └─ Start with time-profiler.md, then memory-profiling.md
│
└─ Pre-release performance audit
└─ Read ALL reference files, use Review Checklist below
快速参考
| 问题 | Instrument/工具 | 关键指标 | 参考 |
|---|---|---|---|
| UI 卡顿 > 250ms | Time Profiler + Hangs | 卡顿时长、主线程堆栈 | time-profiler.md |
| 滚动/动画卡顿 | Animation Hitches 模板 | 卡顿时间比率(< 5 ms/s 良好,> 10 严重) | hitches.md |
| CPU 使用率高 | Time Profiler / CPU Profiler | 各函数的 CPU %、调用树权重 | time-profiler.md |
| 内存泄漏 | Leaks + Memory Graph | 泄漏字节数、保留环路径 | memory-profiling.md |
| 内存增长 | Allocations | 存活字节数、代际分析 | memory-profiling.md |
| 启动缓慢 | App Launch | 首帧时间(主程序前 + 主程序后) | launch-optimization.md |
| 电池耗电 | Energy Log / Power Profiler | 能耗影响评分、CPU/GPU/网络 | energy-diagnostics.md |
| 温度问题 | Activity Monitor | 温度状态转换 | energy-diagnostics.md |
| 网络浪费 | Network profiler | 冗余请求、大型负载 | energy-diagnostics.md |
8 项关键指标(WWDC21 10181)
Apple 明确列出了应用性能需要跟踪的 8 项指标,均可通过 5 种工具(Xcode Organizer、MetricKit、Instruments、XCTest、App Store Connect API)覆盖:
| # | 指标 | 阈值/信号 | 工具 |
|---|---|---|---|
| 1 | 电池使用量 | Energy Gauge 将 CPU 使用率 > 20% 标记为 CPU 使用率高,并显示 CPU 唤醒开销区域;需关注的主要子系统:CPU、网络、定位 | Energy Gauge → Time Profiler |
| 2 | 启动时间 | 从点击图标到渲染出首帧的时间 | App Launch 模板、XCTApplicationLaunchMetric |
| 3 | 卡顿率 | 输入无响应时间 ≥ 250ms | Hangs instrument、Organizer |
| 4 | 内存 | Organizer 图表显示 峰值内存和挂起时的内存;出现峰值但尚未出现终止峰值时,就是早期预警 | Allocations、Leaks、VM Tracker |
| 5 | 磁盘写入 | 应用在 24 小时内写入 > 1 GB 时生成异常报告(包含堆栈跟踪和 Insights 注释) | File Activity 模板、XCTStorageMetric |
| 6 | 滚动 | Organizer 滚动图表中的红色条形表示滚动体验不佳,应立即修复 | Animation Hitches、XCTOSSignpostMetric.scrollDecelerationMetric |
| 7 | 终止 | 每次终止都会导致下次启动时进行缓慢的冷启动,并丢失用户状态 | MXAppExitMetric、Organizer |
| 8 | MXSignposts | 为关键代码段添加自定义标记的时间间隔 | MetricKit |
Organizer 会汇总已授权用户设备上的所有这些数据,涵盖最近 16 个应用版本;Regressions 面板(Xcode 13)会集中显示最新版本中所有显著增加的指标。同一数据也可通过 App Store Connect API 以 JSON 格式获取(WWDC21 10181)。
流程
1. 确定问题类别
询问用户或检查其描述,以对问题进行分类:
- 响应能力:卡顿、迟滞、动画丢帧
- 内存:泄漏、增长、OOM 崩溃
- 启动:冷启动/热启动缓慢
- 能耗:电池耗电、温度节流
2. 阅读相应的参考文件
每个文件都包含:
- 要使用的 Instruments 模板
- 逐步执行的性能分析工作流
- 如何解读结果
- 常见修复模式及代码示例
3. 在真实硬件上进行性能分析
务必提醒用户:
- 在设备上进行性能分析,不要使用 Simulator(Simulator 使用主机的 CPU/内存)
- 使用 Release 构建配置(优化会改变行为)
- 使用 有代表性的数据进行性能分析(空数据库会掩盖真实的性能问题)
- 关闭其他应用以减少干扰
4. 应用修复并验证
识别瓶颈后:
- 应用参考文件中的针对性修复
- 重新进行性能分析以确认改进
- 添加
os_signpost标记以便持续监控
Xcode 诊断设置
建议在 Scheme > Run > Diagnostics 中启用以下设置:
| 设置 | 检测内容 |
|---|---|
| Main Thread Checker | 在主线程以外执行 UI 工作 |
| Thread Sanitizer | 数据竞争 |
| Address Sanitizer | 缓冲区溢出、释放后使用 |
| Malloc Stack Logging | 内存分配调用堆栈 |
| Zombie Objects | 向已释放的对象发送消息 |
MetricKit 集成
对于生产环境监控,建议使用 MetricKit(WWDC20 10081、WWDC21 10181):
import MetricKit
final class PerformanceReporter: NSObject, MXMetricManagerSubscriber {
func startCollecting() {
MXMetricManager.shared.add(self) // subscribe once, early in launch
}
// best practice: remove(self) in deinit (WWDC21 10181)
func didReceive(_ payloads: [MXMetricPayload]) {
for payload in payloads {
// Launch time
if let launch = payload.applicationLaunchMetrics {
log("Resume time: \(launch.histogrammedResumeTime)")
}
// Hang rate
if let responsiveness = payload.applicationResponsivenessMetrics {
log("Hang time: \(responsiveness.histogrammedApplicationHangTime)")
}
// Memory
if let memory = payload.memoryMetrics {
log("Peak memory: \(memory.peakMemoryUsage)")
}
// Scroll hitches (ratio of time hitching to time scrolling)
if let animation = payload.animationMetrics {
log("Scroll hitch ratio: \(animation.scrollHitchTimeRatio)")
}
// Exit reasons — daily counts per termination cause, fg + bg
if let exits = payload.applicationExitMetrics {
log("Exits: \(exits.backgroundExitData)")
}
}
}
func didReceive(_ payloads: [MXDiagnosticPayload]) {
for payload in payloads {
if let hangs = payload.hangDiagnostics {
for hang in hangs {
log("Hang: \(hang.callStackTree)")
}
}
}
}
}
要点(WWDC20 10081、WWDC21 10181):
- ❌ 延迟订阅(例如在设置界面中订阅)会导致已送达的负载被悄然遗漏——✅ 在 App/AppDelegate 初始化时订阅;前一天的负载会在启动时交给你。
- 指标以 24 小时负载形式送达,每天最多一次,包含三种聚合形式:累积、平均和分桶(
MXHistogram)。在 iOS 15+/macOS 12+ 上,所有诊断信息都会在问题发生后立即送达,而不是每天送达。 - 终止和内存遥测信息默认包含在每日指标负载中——无需额外插桩。
- 诊断类型:
MXHangDiagnostic(主线程无响应时长 + 回溯)、MXCrashDiagnostic(异常信息、终止原因、VM 区域信息)、MXCPUExceptionDiagnostic(消耗 CPU 的线程——Organizer 能耗日志的编程形式)、MXDiskWriteExceptionDiagnostic(达到每天 1 GB 写入阈值时触发)。 MXCallStackTree回溯按设计不会进行符号化——使用atos类工具和你的 dSYM 在设备外进行符号化;❌ 不要尝试在设备上进行。MXSignpost标记关键代码段,以收集实地遥测数据;动画变体会捕获该时间段的卡顿率遥测数据:
let handle = MXMetricManager.makeLogHandle(category: "animation_telemetry")
mxSignpostAnimationIntervalBegin(log: handle, name: "custom_animation")
// ... animation ...
mxSignpost(OSSignpostType.end, log: handle, name: "custom_animation")
审查清单
响应速度
- 主线程上没有耗时超过 100ms 的同步工作
- 主线程上没有文件 I/O 或网络调用
- 大型查询的 Core Data / SwiftData 获取操作使用后台上下文
- 在主线程以外解码图像(使用
.preparingThumbnail或异步解码) - 仅在确实需要访问 UI 的代码上使用
@MainActor
内存
- 没有循环引用(检查委托模式、使用
self的闭包) - 不可见时释放大型资源(图像、缓存)
- 集合不会无限增长(限制缓存、分页)
- 在创建 ObjC 对象的紧密循环中使用
autoreleasepool
启动时间
- 不在
@main App结构体的init()中执行繁重工作 - 延迟非必要的初始化(分析、预取)
- 尽量减少动态框架(优先使用静态链接)
- 启动时没有同步网络调用
能耗
- 后台任务适当使用
BGProcessingTaskRequest - 定位精度符合实际需求(不要总是使用
.best) - 计时器使用
tolerance以便合并触发 - 尽可能批量处理网络请求
参考资料
- time-profiler.md — CPU 性能分析、卡顿检测阶梯、signpost API、Instruments 27 种工具
- hitches.md — 渲染循环、卡顿时间比、提交/渲染阶段修复目录
- memory-profiling.md — Allocations、Leaks、内存图调试器、memgraph CLI、终止原因
- launch-optimization.md — 应用启动阶段、冷启动/热启动优化、链接器调优手段
- energy-diagnostics.md — 电池、热状态、网络效率、Power Profiler
- WWDC:终极应用性能生存指南
- WWDC:了解并消除应用卡顿
- WWDC:使用 Xcode 和设备端检测追踪卡顿
- WWDC:使用 Instruments 分析卡顿
- WWDC:检测和诊断内存问题
- WWDC:分析堆内存
- WWDC:我的应用为什么会被终止?
- WWDC:MetricKit 新功能
- WWDC:优化应用启动
- WWDC:使用 Instruments 优化 CPU 性能
- WWDC:分析并优化应用耗电量
- WWDC:分析、修复并验证——使用 Instruments 提升应用响应速度
评论
支持 Markdown