死锁(Deadlock)原理、常见场景与治理

死锁是 iOS 多线程开发中最隐蔽、也最致命的一类稳定性问题。它不像越界、空指针那样"立刻崩溃给你看",而是表现为主线程"卡住"——用户能感受到界面无响应、无法交互,最终被 iOS watchdog 强杀(0x8BADF00D),落在 Apple 崩溃日志里归为 EXC_CRASH (SIGKILL) 或卡死(Hang)。 本文系统梳理死锁的四个必要条件、iOS 生产环境中常见的发生场景,并结合 Apple 官方工具(TSan、Main Thread Checker、MetricKit)与业界最新实践(Sentry App Hangs、字节 Heimdallr、Swift Concurrency 的反思)讨论如何检测与治理。 一、死锁是什么 死锁(Deadlock)指两个或多个线程因争夺资源(锁、队列、信号量等)而互相等待,导致所有相关线程永久阻塞、无法推进的状态。 与死锁容易混淆的几个概念: 名称 核心特征 典型例子 死锁 Deadlock 多个线程循环等待对方持有的资源,永久阻塞 线程 A 持 lockA 等 lockB;线程 B 持 lockB 等 lockA 活锁 Livelock 线程不阻塞但也不推进,不停重试互相让步 两个线程都检测到冲突就回退重试,永远撞在一起 饥饿 Starvation 低优先级线程长期分不到资源 高优先级线程持续抢占 CPU,导致低优先级线程持锁永远运行不完 优先级反转 Priority Inversion 低优先级持锁 + 高优先级自旋等锁 + 中优先级抢 CPU,高优先级被间接阻塞 OSSpinLock 被废弃的根本原因 死循环 Busy Loop 单线程进入无限循环,CPU 占用 100% while(true) 忘记 break 卡顿 Hang 主线程执行时间超过阈值(几百 ms~几秒) 主线程做网络、解压大图、Core Data 大量 fetch 卡死 Watchdog 主线程卡住数秒(启动约 20s、前后台切换约 10s),触发系统强杀 死锁导致的卡死是最严重的一种 关键区别:死循环线程 CPU 占用高、处于 RUNNING 态;死锁线程 CPU 占用为 0、处于 WAITING/BLOCKED 态并被换出。这一点正是线上死锁自动判定的核心依据(见"检测"章节)。 ...

May 4, 2026