mcpField
P
performance-profiling

performance-profiling

github.com/rshankras测试与质量84482 次安装14 周前更新
代码仓库

关于 performance-profiling

面向 Apple 平台应用开发者的性能分析指南,涵盖 Instruments、Xcode 诊断和 MetricKit。按响应、内存、启动与能耗问题提供分析流程和修复建议。

主要功能

  1. 01分析 CPU、内存、启动与能耗
  2. 02按性能问题选择分析工具
  3. 03提供逐步分析流程和修复模式
  4. 04使用 MetricKit 监控线上表现
  5. 05列出性能审查清单

适用场景

  1. 01排查界面卡顿和丢帧
  2. 02定位内存泄漏或内存增长
  3. 03优化应用启动时间
  4. 04诊断耗电和热量问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rshankras/claude-code-apple-skills --skill performance-profiling

安装后在 Claude Code 中输入/performance-profiling确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

energy-diagnostics.md
hitches.md
launch-optimization.md
memory-profiling.md
time-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 卡顿 > 250msTime 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卡顿率输入无响应时间 ≥ 250msHangs 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
8MXSignposts为关键代码段添加自定义标记的时间间隔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 以便合并触发
  • 尽可能批量处理网络请求

参考资料

评论

支持 Markdown