先让它别再重启
这次 Codex Desktop 的问题,一开始不是突然坏掉,而是越来越卡。
先是输入、切换任务、打开页面都变慢。后来开始卡死,重启以后会短暂好一点,但用一会儿又慢回来。最麻烦的一次,是我误触了一个临时修复脚本:它会退出 Codex,再重启 Codex,然后又被触发一次,最后变成循环重启。
这种状态很吓人,因为它看起来像“应用自己疯了”。最后我查出了几处同时存在的问题:本地数据异常膨胀、SQLite 状态库和 WAL 写盘压力、残留 helper、工作区里的大量 diff、未跟踪文件和多个 worktree。
我先停掉循环,确认没有 LaunchAgent、cron 或残留进程继续引用那个脚本,再把临时脚本移除。只有这一步做完,后面的排查才有意义。否则每次刚查到一半,应用又被重启,所有判断都会被打断。
- 单次执行:跑完一次就退出,不自动重复。
- 带锁:已经在执行时,第二次触发直接退出。
- 可观察:至少留下开始时间、结束时间和做了什么。
- 可回滚:能清楚知道怎么关闭、移除并恢复原状态。
尤其是“自动退出并重启应用”这种脚本,不能写成无限循环。它看起来是在救火,失控以后就是新的火。
别只盯着 Git
我一开始也怀疑过:是不是本地有 4.5 万行变更没 push 到 GitHub,所以 Codex 首次打开特别慢?
后来实测下来,这个判断不对。当前 git status 大约 0.01 秒,这个速度说明 Git 本身不是这次卡顿的根因。
但这不代表工作区完全没影响。大量未提交 diff、未跟踪文件、重复 worktree,都会让编辑器、搜索和上下文扫描更累。它们属于“工作区负担”,和 Codex 自己的数据层负担要分开看。
Codex 数据层
本地会话、归档、SQLite 状态数据库、WAL,以及残留 helper 进程。
Git 工作区层
未提交 diff、未跟踪文件、生成物、重复 worktree,以及 commit 与 push 的状态。
这两层都会影响体感,但处理方式完全不同。把它们混在一起,很容易越修越乱。
15.3 GB 到底是什么
事故前,Codex 本地数据目录大约 15.3 GB。这个体积已经不适合只靠“重启一下”解决。
里面最明显的是 Codex 本地状态数据库和 SQLite 的预写日志 WAL。旧状态库大约 1,001,451,520 bytes,WAL 大约 125,486,992 bytes。对一个持续读写会话和状态的桌面应用来说,这种异常膨胀会明显放大写盘压力。
重启只能暂时清掉一部分进程和内存状态,不能替代数据库健康检查,也不会自动处理 WAL、残留 helper 或工作区负担。所以我没有把“重启后变顺”当成修好了。
修复后并不是把历史删光。
本地目录仍约 14 GB,主要是会话和归档,因为我保留了任务历史。真正明显收缩的是状态数据库和 WAL:状态库约 269 MB,WAL 约 9.6 MB,SQLite quick_check 返回 ok。
这次处理的目标,是把异常膨胀和持续写盘压力收回来,不是用“清空一切”换一个暂时变快的 Codex。
残留 helper 也要单独查
Codex 退出以后,相关 helper 不一定都会马上消失。尤其是长会话、终端任务或浏览器工具运行过以后,后台可能还留着一些进程。
我先记录进程状态,再退出 Codex,观察哪些进程会正常消失,哪些仍然留在后台。确认进程归属后,才处理确实残留的部分,不看到相似名字就一把全杀。
这一步也不能只靠“重启以后不卡了”判断。helper 如果会被异常任务再次拉起,或者状态库仍在持续写盘,问题过一会儿还是会回来。
159 个文件不能一把梭
这次工作区里还有 159 个未跟踪文件。这里最容易犯两个错误:一个是 git add .,一个是全删。
未跟踪文件里可能混着源码、生成物、截图、缓存、重复件和临时文件。git add . 会把不该进仓库的东西一起带进去;全删又可能把还没整理的有效改动删掉。
我更稳的做法是分类:源码和配置逐个确认;生成物和截图先看能不能重新生成;重复件和旧备份确认已经迁移,再清理;看不准的文件先放进受控备份,不直接删除。
这一步慢一点没关系。真正危险的是为了让 git status 变干净,一口气把所有东西加进去,或者一口气删掉。
13 个 worktree 怎么收
当时实际存在 13 个 worktree。这个数量已经很容易让人搞混:到底哪个是主工作区,哪个只是临时验证,哪个有改动还没迁回主线。
我后面把它们逐个核对、备份并清理到 1 个主工作区,约释放 3.8 GB。需要保留的分支和内容都先留下,再移除已经不用的旧 worktree。
这里我现在会坚持一个原则:先确认主工作区,再处理旧 worktree。不要从旧 worktree 直接发布,也不要在多个 worktree 之间来回改同一份内容。
我现在会按这个顺序查
如果下次 Codex Desktop 又开始卡,我会先止血。看有没有脚本、自动任务或残留进程在反复退出和重启应用。这个不处理,后面所有排查都会被打断。
然后只读取证:目录体积、状态库大小、WAL 大小、进程状态、Git 状态耗时、worktree 数量、未跟踪文件数量。先记事实,不要边猜边删。
接着分层。会话、状态库、WAL 和 helper 归 Codex 数据层;diff、未跟踪文件、worktree、commit 和 push 归 Git 工作区层。
再安全整理。未跟踪文件分类,worktree 先备份和迁移,确认主工作区,再做清理。能 commit 的按产品边界 commit,不能确认的先保留证据。
最后复测。不能只凭“体感顺了”就停。至少要看 Git 状态速度、应用重启后是否还卡、残留进程是否消失、关键项目验证是否通过。
这次完整收口后,我跑了几组验证:前台 build、lint、浏览器测试 39/39,工具测试 82/82,运营看板 7/7,运维只读巡检 18/18。这些都通过以后,我才确认这次排查结束。
4.5 万行和 push 的真相
这点单独拎出来说,是因为太容易误会。
本地有很多改动时,Codex、编辑器、搜索和索引确实会更累。尤其是没 commit 的大 diff,会让很多工具在读取上下文时背上额外负担。
commit 是本地收口
把确认要保留的改动写进本地历史,工作区不再背着同一批 diff。
push 是远端同步
把本地提交同步到 GitHub,方便备份、协作和部署,不是本机性能开关。
所以“没 push 到 GitHub”不是本地首次打开变慢的直接原因。正确顺序是先确认哪些改动该保留,按产品、按主题 commit,再推送到远端。不要把 push 当成性能修复,也不要因为没 push 就误判卡顿根因。
下次先做这几件事
下次再遇到 Codex Desktop 卡顿、卡死,我不会先重装,也不会先清空目录。
- 停掉所有会自动退出、重启应用的临时脚本。
- 看 Codex 本地数据目录、状态数据库和 WAL 是否异常变大。
- 查有没有残留 helper 或重复进程。
- 测一次
git status,用数据判断 Git 是否真的慢。 - 统计未跟踪文件,不
git add .,也不直接全删。 - 确认 worktree 数量,只从主工作区继续做新任务。
- 能 commit 的先 commit,push 只当远端同步。
这是一台机器上的真实排查顺序,不代表所有 Codex 卡顿都只有同一个原因。但把“止血、取证、分层、整理、复测”这五步记住,至少不会在最卡的时候继续制造新问题。
后面我会把 Codex 系列继续拆开写:桌面端数据目录怎么安全检查,worktree 和未跟踪文件怎么整理,以及 Codex 项目里 commit、push、部署到底该怎么分开看。