这个卡死堆栈涉及到 FrontBoardServices 的场景快照请求,是一个典型的 系统级死锁问题。以下是详细分析和解决方案:
堆栈分析
关键组件说明
- FrontBoardServices (FBS):iOS 的窗口和场景管理服务
- FBSSceneSnapshotRequest:场景快照请求(用于多任务切换、应用截图等)
-
信号量等待:
dispatch_semaphore_wait_slow表明线程在等待某个资源
死锁发生位置
4 FrontBoardServices -[FBSSceneSnapshotRequestHandle performRequestForScene:] + 636
5 FrontBoardServices -[FBSSceneSnapshotAction snapshotRequest:performWithContext:] + 208
6 FrontBoardServices -[FBSSceneSnapshotRequest performSnapshotWithContext:] + 224
死锁原因分析
1. 主线程阻塞导致快照无法完成
// 可能的阻塞场景
- (void)viewDidLoad {
[super viewDidLoad];
// ❌ 危险:主线程同步网络请求
NSData *data = [NSData dataWithContentsOfURL:url];
// ❌ 危险:主线程大量计算
for (int i = 0; i < 1000000; i++) {
// 耗时计算
}
// ❌ 危险:主线程文件操作
NSString *largeFile = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
}
2. 视图渲染性能问题
// 视图渲染导致的卡顿
- (void)drawRect:(CGRect)rect {
// ❌ 复杂图形绘制
for (int i = 0; i < 1000; i++) {
CGContextDrawPath(context, kCGPathFillStroke);
}
// ❌ 大量图层操作
for (UIView *subview in self.subviews) {
subview.layer.shadowOpacity = 0.5;
subview.layer.cornerRadius = 10;
}
}
3. 自定义转场动画冲突
// 自定义转场与系统快照冲突
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
// ❌ 长时间动画阻塞主线程
[UIView animateWithDuration:5.0 animations:^{
// 长时间动画
}];
}
解决方案
方案一:主线程性能优化
// 主线程工作负载优化
@implementation MainThreadOptimizer
// 1. 检测主线程阻塞
- (void)setupMainThreadMonitor {
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopBeforeWaiting:
// 主线程空闲
self.lastIdleTime = [NSDate date];
break;
case kCFRunLoopAfterWaiting:
// 检查是否阻塞太久
if (self.lastIdleTime && [[NSDate date] timeIntervalSinceDate:self.lastIdleTime] > 0.5) {
NSLog(@"⚠️ 主线程可能阻塞: %.2fs", [[NSDate date] timeIntervalSinceDate:self.lastIdleTime]);
[self recoverFromBlocking];
}
break;
}
});
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
}
// 2. 异步处理耗时操作
- (void)asyncProcessHeavyWork {
// ✅ 安全:后台处理数据
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
// 回到主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithData:data];
});
});
}
// 3. 视图渲染优化
- (void)optimizeViewRendering {
// 使用 Instruments 识别性能瓶颈
[self enableRenderingOptimizations];
}
- (void)enableRenderingOptimizations {
// 减少图层混合
self.view.layer.opaque = YES;
// 减少阴影复杂度
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
// 使用光栅化缓存静态内容
self.view.layer.shouldRasterize = YES;
self.view.layer.rasterizationScale = [UIScreen mainScreen].scale;
}
@end
方案二:快照请求处理优化
// 系统快照请求的预处理
@implementation SnapshotRequestHandler
// 1. 准备快照前的状态
- (void)prepareForSnapshot {
// 确保主线程空闲
[self ensureMainThreadReady];
// 暂停非必要动画
[self pauseNonEssentialAnimations];
// 简化视图层次
[self simplifyViewHierarchyForSnapshot];
}
// 2. 主线程准备检查
- (void)ensureMainThreadReady {
// 检查主线程是否忙碌
if ([self isMainThreadBusy]) {
NSLog(@"⚠️ 主线程忙碌,延迟快照准备");
[self performSelector:@selector(ensureMainThreadReady) withObject:nil afterDelay:0.1];
return;
}
// 完成准备工作
[self completePreparation];
}
// 3. 动画管理
- (void)pauseNonEssentialAnimations {
// 暂停自定义动画
for (UIView *view in [self findAllAnimatingViews]) {
[view.layer removeAllAnimations];
}
// 暂停视频播放
[self pauseMediaPlayback];
}
// 4. 视图层次简化
- (void)simplifyViewHierarchyForSnapshot {
// 临时隐藏复杂视图
for (UIView *complexView in [self findComplexViews]) {
complexView.hidden = YES;
}
// 减少透明度
self.view.alpha = 1.0;
}
// 5. 应用状态通知处理
- (void)setupApplicationStateObservers {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
- (void)applicationWillResignActive:(NSNotification *)notification {
// 应用即将进入后台,准备快照
[self prepareForSnapshot];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification {
// 恢复视图状态
[self restoreViewHierarchy];
}
@end
方案三:自定义快照处理
// 自定义快照生成以避免系统死锁
@interface CustomSnapshotGenerator : NSObject
@property (nonatomic, weak) UIWindow *window;
@end
@implementation CustomSnapshotGenerator
// 1. 主动生成快照
- (UIImage *)generateCustomSnapshot {
// 在后台线程生成快照
__block UIImage *snapshot = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// 确保主线程空闲
[self waitForMainThreadIdle];
// 在主线程生成快照
dispatch_async(dispatch_get_main_queue(), ^{
@try {
snapshot = [self safeSnapshot];
} @catch (NSException *exception) {
NSLog(@"❌ 快照生成失败: %@", exception);
} @finally {
dispatch_semaphore_signal(semaphore);
}
});
});
// 等待快照生成完成
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return snapshot;
}
// 2. 安全的快照生成
- (UIImage *)safeSnapshot {
// 使用替代方案生成快照
UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, 0);
@try {
// 方法1: 使用layer渲染
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
// 方法2: 使用drawViewHierarchy (更安全)
// [self.window drawViewHierarchyInRect:self.window.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
return image;
} @catch (NSException *exception) {
NSLog(@"❌ 快照异常: %@", exception);
return nil;
} @finally {
UIGraphicsEndImageContext();
}
}
// 3. 主线程空闲等待
- (void)waitForMainThreadIdle {
// 等待主线程变为空闲状态
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:2.0];
while ([self isMainThreadBusy] && [timeout timeIntervalSinceNow] > 0) {
[NSThread sleepForTimeInterval:0.01];
}
if ([timeout timeIntervalSinceNow] <= 0) {
NSLog(@"⚠️ 主线程持续忙碌,强制生成快照");
}
}
// 4. 主线程忙碌检测
- (BOOL)isMainThreadBusy {
// 检查RunLoop状态
CFRunLoopActivity activity = CFRunLoopGetActivity(CFRunLoopGetMain());
return activity != kCFRunLoopBeforeWaiting;
}
@end
方案四:死锁检测和恢复
// 死锁检测和自动恢复机制
@interface DeadlockDetector : NSObject
@property (nonatomic, assign) NSTimeInterval lastSnapshotTime;
@property (nonatomic, assign) BOOL snapshotInProgress;
@end
@implementation DeadlockDetector
+ (instancetype)shared {
static DeadlockDetector *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[DeadlockDetector alloc] init];
});
return instance;
}
// 1. 启动死锁监控
- (void)startDeadlockMonitoring {
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkForDeadlock) userInfo:nil repeats:YES];
}
// 2. 死锁检测
- (void)checkForDeadlock {
// 检查快照请求是否卡住
if (self.snapshotInProgress) {
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:self.lastSnapshotTime];
if (duration > 3.0) { // 3秒超时
NSLog(@"⚠️ 检测到快照死锁,持续时间: %.2fs", duration);
[self recoverFromSnapshotDeadlock];
}
}
}
// 3. 快照开始标记
- (void)snapshotWillStart {
self.snapshotInProgress = YES;
self.lastSnapshotTime = [NSDate date];
}
// 4. 快照完成标记
- (void)snapshotDidComplete {
self.snapshotInProgress = NO;
}
// 5. 死锁恢复
- (void)recoverFromSnapshotDeadlock {
NSLog(@"🔄 执行快照死锁恢复");
// 强制取消所有快照请求
[self cancelPendingSnapshots];
// 释放可能阻塞的资源
[self releaseBlockingResources];
// 重置状态
self.snapshotInProgress = NO;
// 生成替代快照
[self generateAlternativeSnapshot];
}
- (void)cancelPendingSnapshots {
// 尝试中断快照进程
[[NSNotificationCenter defaultCenter] postNotificationName:@"CancelSnapshotOperations" object:nil];
}
- (void)generateAlternativeSnapshot {
// 使用自定义快照生成器
CustomSnapshotGenerator *generator = [[CustomSnapshotGenerator alloc] init];
UIImage *snapshot = [generator generateCustomSnapshot];
if (snapshot) {
// 保存快照供系统使用
[self cacheSnapshot:snapshot];
}
}
@end
方案五:性能监控和预警
// 性能监控系统
@interface PerformanceMonitor : NSObject
@property (nonatomic, strong) NSMutableArray *performanceMetrics;
@end
@implementation PerformanceMonitor
// 1. 监控主线程性能
- (void)monitorMainThreadPerformance {
// 监控CPU使用率
[self monitorCPUUsage];
// 监控内存使用
[self monitorMemoryUsage];
// 监控渲染性能
[self monitorRenderingPerformance];
}
// 2. CPU监控
- (void)monitorCPUUsage {
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkCPUUsage) userInfo:nil repeats:YES];
}
- (void)checkCPUUsage {
double cpuUsage = [self getMainThreadCPUUsage];
if (cpuUsage > 80.0) { // 80%阈值
NSLog(@"⚠️ 主线程CPU使用率过高: %.1f%%", cpuUsage);
[self throttleBackgroundWork];
}
}
// 3. 内存监控
- (void)monitorMemoryUsage {
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(checkMemoryUsage) userInfo:nil repeats:YES];
}
- (void)checkMemoryUsage {
uint64_t memoryUsage = [self getAppMemoryUsage];
if (memoryUsage > 100 * 1024 * 1024) { // 100MB阈值
NSLog(@"⚠️ 内存使用过高: %llu MB", memoryUsage / 1024 / 1024);
[self clearCaches];
}
}
// 4. 预警系统
- (void)setupPerformanceAlerts {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(performanceAlert:)
name:@"PerformanceAlert"
object:nil];
}
- (void)performanceAlert:(NSNotification *)notification {
NSDictionary *info = notification.userInfo;
NSString *alertType = info[@"type"];
if ([alertType isEqualToString:@"SnapshotDeadlockImminent"]) {
// 快照死锁预警,提前采取措施
[self preventSnapshotDeadlock];
}
}
- (void)preventSnapshotDeadlock {
// 提前简化视图层次
[self preemptivelySimplifyUI];
// 暂停非关键操作
[self pauseNonCriticalOperations];
// 准备快速快照
[self prepareForQuickSnapshot];
}
@end
预防措施总结
- 主线程优化:避免阻塞操作,使用异步处理
- 视图渲染优化:减少复杂图层和动画
- 快照预处理:在系统快照前准备应用状态
- 死锁检测:监控和自动恢复机制
- 性能监控:实时监控并预警性能问题
通过上述方案,可以显著减少因系统快照请求导致的死锁问题,提高应用稳定性。