起因

昨天(7月7日)升级了 macOS 27 Beta 3 之后,我的 MacBook Air M2 就一直不对劲——CPU 温度稳定在 80°C 到 90°C 之间,风扇?不,Air 根本没有风扇,只能靠被动散热硬扛。键盘摸上去都是温热的,电池续航也肉眼可见地往下掉。

重启了好几次,没用。Activity Monitor 里看 CPU 占用率也不高,这就很奇怪了——负载不高为什么会高温?

于是我把这个问题丢给了本地的 AI 智能体,让它帮我排查。以下是整个排查过程的记录。

第一轮:先看看基本情况

智能体先收集了一轮基础信息:

1
2
3
sysctl -n machdep.cpu.brand_string    # → Apple M2
top -l 1 # 进程概览
vm_stat # 虚拟内存状态

几个关键发现:

  • 用户态 CPU 17%,但系统态 CPU 高达 37%,总负载约 60%。这说明问题不在用户应用层,而在系统内核层面。
  • 内存极度紧张:仅约 80MB 空闲,超过 1GB 被压缩,已经动用 swap 了。
  • MacBook Air M2 无风扇,被动散热,任何持续负载都容易积热。

这个系统态 CPU 占比非常反常,正常情况应该在个位数。

第二轮:谁在偷 CPU?

ps 命令按 CPU 占用排序:

1
ps axo pid,pcpu,pmem,comm -r

结果一出,直接傻眼:

进程 CPU 占用 正常值
launchd (PID 1) 200% <1%
logd (PID 98) 101% <1%
claude 15% 正常

launchd 是 macOS 的 PID 1 进程,相当于 Linux 的 systemd,是所有系统服务的”大管家”。正常情况下它几乎不消耗 CPU,现在却吃满了两个完整核心。logd 也飙到了 100%+,说明有东西在疯狂写日志。

第三轮:launchd 在忙什么?

进一步排查 launchd 管理的服务状态:

1
2
launchctl list                      # 所有系统服务状态
systemextensionsctl list # 系统扩展

炸裂的发现:

  1. 166 个系统服务状态为 SIGKILL (-9)——被系统强制杀掉了。包括 clouddbirdcontactsdtccdcloudphotod 等等,几乎覆盖了 iCloud 同步、通讯录、隐私权限等全部系统服务。
  2. 某安全软件每 10-20 秒崩溃一次,7 分钟内产生了 25 份崩溃报告,崩溃类型是 EXC_BAD_ACCESS / SIGSEGV

第四轮:第一次尝试修复(失败)

这时候的推测是:某安全软件的系统扩展频繁崩溃 → launchd 反复重启它 → 恶性循环。

于是尝试卸载它:

1
sudo launchctl unload /Library/LaunchDaemons/com.xxx.xxx.daemon.plist

无效。因为它是 System Extension(系统扩展),不受 launchctl 控制。

换用系统扩展卸载命令:

1
sudo systemextensionsctl uninstall FN2V63AD2J com.xxx.xxx.fileguard

SIP(系统完整性保护) 拦下来了。

最后手动 killall 掉所有相关进程然后重启。重启后确认该安全软件已经被清除,但——launchd 仍然 175% CPU

问题依旧。说明该安全软件只是被波及的受害者,不是根因。

第五轮:重新找根因

换个思路,全面检查系统状态:

1
2
launchctl print system     # 系统域活跃项:1073 个
launchctl print gui/501 # GUI 域活跃项:456 个

然后检查 LaunchAgent 和 LaunchDaemon 的文件属性:

1
2
3
xattr -l /Library/LaunchAgents/*.plist
xattr -l /Library/LaunchDaemons/*.plist
xattr -l ~/Library/LaunchAgents/*.plist

这时候智能体搜到一篇文章,指向了 macOS 27 Beta 3 的一个已知 Bug

macOS 27 Beta 3 的 launchd 无法正确加载带有 com.apple.quarantine 属性的 .plist 文件,会陷入无限重试循环。

验证发现某输入法的两个 plist 果然带有 quarantine 属性:

1
2
/Library/LaunchAgents/com.xxx.xxxServices.plist   → QUARANTINE
/Library/LaunchAgents/com.xxx.xxxTaskManager.plist → QUARANTINE

第六轮:修好又复发

移除这两个文件的 quarantine 属性:

1
2
sudo xattr -d com.apple.quarantine /Library/LaunchAgents/com.xxx.xxxServices.plist
sudo xattr -d com.apple.quarantine /Library/LaunchAgents/com.xxx.xxxTaskManager.plist

重启后 launchd 正常了!——但 8 分钟后再次飙到 197%。

原因很简单:某输入法不是唯一带 quarantine 的。某清理软件一启动,它的 plist 也带 quarantine,又触发了同样的 Bug。

第七轮:全量扫描,彻底根除

写了个脚本全量扫描所有 LaunchAgents 和 LaunchDaemons:

1
2
3
4
5
6
for f in /Library/LaunchAgents/*.plist /Library/LaunchDaemons/*.plist \
~/Library/LaunchAgents/*.plist; do
[ -f "$f" ] && \
attr=$(xattr -l "$f" 2>/dev/null | grep quarantine) && \
echo "[QUARANTINE] $f"
done

最终找到 6 个带 quarantine 的文件

文件 来源
com.xxx.xxxServices.plist 某输入法
com.xxx.xxxTaskManager.plist 某输入法
com.xxx.xxxMonitor.plist 某清理软件
com.xxx.xxx.plist 某清理软件
com.xxx.keystone.agent.plist 某浏览器更新器
com.xxx.keystone.xpcservice.plist 某浏览器更新器

全部移除 quarantine 属性后重启——✅ 问题彻底解决。CPU 温度回到 40-50°C 的正常范围,内存也释放了,166 个系统服务全部恢复正常运行。

完整的根因链

整个问题的因果链条其实非常清晰:

1
2
3
4
5
6
7
8
macOS 27 Beta 3 的 launchd Bug
→ 无法加载带 com.apple.quarantine 的 plist
→ 某输入法 / 某清理软件 / 某浏览器更新器的 plist 带 quarantine(这是 macOS 的正常安全行为)
→ launchd 反复尝试加载 → 失败 → 重试 → 无限循环
→ launchd 200% CPU + logd 100% CPU(疯狂写日志)
→ 内存被耗尽 → 系统 SIGKILL 掉 166 个后台服务
→ launchd 又要重启这 166 个被杀的服务 → 内存更紧张
→ M2 MacBook Air 无风扇 → 持续高负载无法散热 → 🔥 高温

总结

几个 takeaways:

  1. 这不是任何第三方软件的锅。macOS 给下载的软件打上 com.apple.quarantine 标记是正常的安全机制,它们在稳定版系统上完全没问题。根因是 Beta 3 的 launchd 存在 Bug。
  2. 临时修复sudo xattr -d com.apple.quarantine 移除受影响 plist 的隔离属性。
  3. 彻底修复:目前我暂未找到合适的方法。除了临时修复外只能希望 Apple 在发布下一个 Beta 时可以修掉 launchd 的 Bug。
  4. 排查问题要沉住气。这次排查经历了七轮,中间还被一个表象(某安全软件频繁崩溃)误导了一次。清掉它之后问题依旧的那一瞬间,说不沮丧是假的。但重新回到数据上,找到 quarantine 这个线索之后,一切就豁然开朗了。

这次经历也让我切实体会了一把——有个 AI 智能体帮你一步步跑命令、分析输出、搜索资料,排查效率确实比纯手工高太多了。它也并没有一步到位,而是像人一样在反复试错、修正假设、重新出发。这个过程本身就很有意思。


如果你也遇到了类似问题,可以试试上面的一键扫描脚本。当然,日常使用还是不建议在生产机上跑 Beta 系统 😅