跳到主要内容

设计性能监控 SDK

问题

如何设计 iOS 端的性能监控 SDK?

答案

监控维度

卡顿检测(主线程监控)

class JankMonitor {
private let semaphore = DispatchSemaphore(value: 0)
private var isRunning = false
private let threshold: TimeInterval = 0.05 // 50ms 判定卡顿

func start() {
isRunning = true
DispatchQueue.global().async { [weak self] in
while self?.isRunning == true {
self?.semaphore.signal() // 重置信号

var responded = false
DispatchQueue.main.async {
responded = true
self?.semaphore.signal()
}

// 等待主线程响应
let result = self?.semaphore.wait(timeout: .now() + (self?.threshold ?? 0.05))
if result == .timedOut && !responded {
// 主线程卡顿!采集调用栈
let backtrace = Thread.callStackSymbols
ReportManager.report(type: .jank, data: backtrace)
}

Thread.sleep(forTimeInterval: 1)
}
}
}
}

启动耗时采集

class StartupMonitor {
static let processStartTime: TimeInterval = {
var info = mach_timebase_info_data_t()
mach_timebase_info(&info)
let now = mach_absolute_time()
return Double(now) * Double(info.numer) / Double(info.denom) / 1_000_000_000
}()

static func recordFirstFrame() {
let launchTime = CFAbsoluteTimeGetCurrent() - processStartTime
Analytics.track("app_launch_time", params: ["duration": launchTime])
}
}

关键指标

指标目标采集方式
冷启动< 1smach_absolute_time → 首帧
FPS>= 55CADisplayLink 帧回调间隔
卡顿率< 1%主线程信号量超时
内存峰值< 200MBtask_info API

常见面试问题

答案:CADisplayLink 每次屏幕刷新都回调。记录回调次数和时间差,FPS = count / (currentTime - lastTime)。但它只能在主线程不阻塞时工作,所以严重卡顿时 FPS 会直接降为 0。需要配合子线程信号量检测方案互补。

相关链接