leeguoo

# Codex 真在偷偷烧你的 SSD 吗?我在自己机器上扒了一遍

朋友圈在传 Codex 偷偷狂写日志烧 SSD。本机实测:文件靠滚动稳定在 126MB,但 10 天插入 845 万行、写盘的是后台桌面版 app-server——原帖方向基本属实,只有"人人一年必烧光"被夸大。附根因(源码 + GitHub issue)与清理方案。

2026年6月24日 · 文章 · 公开

Codex 会不会写爆 SSD?
我查了本机日志

朋友圈在转一条警告:Codex 会在后台高频写 logs_2.sqlite,文件看着不大,实际写入可能很高。我先以为是夸张标题,查完本机日志后改了判断。

谣言 vs 真相:人群把一个小日志文件当成喷火的硬盘怪物,侦探拿尺子一量文件确实不大
文件只有 126 MB。问题不在体积,而在它背后的插入和删除。

更新 2026-06-24:OpenAI 已承认这个 bug 并合并了修复,#28224 一度关闭——但很快被重新打开,因为最新稳定版 0.142.0 仍没修干净。完整修复只在当天发布的 0.143-alpha 里。本机升级到 0.142.0 后三次实测仍在写,多平台用户复现,连 OpenAI 自己的修复 commit 都点明了原因——详见下文「"更新版本就好了"?」一节。

网上在传什么

我看到两类说法:一类是转发截图,只说 Codex 在烧盘;另一类是 lencx 的源码和 issue 复盘。

转发版的说法是:装了 Codex CLI 后,它会往 ~/.codex/logs_2.sqlite 高频写数据;文件看着没变大,SSD 写入量却在涨。

证据版来自 lencx(浮之静)的 《Codex 日志正在燃烧你的 SSD》。他翻了 Codex 源码和一串 GitHub issue,把问题指向 SQLite 日志层的默认配置:TRACE 级网络事件、遥测镜像和依赖库噪声被写进持久化数据库,文件大小不能代表实际写入量。

我按这个方向查了自己的机器。下面只放本机命令和能核对的 issue,不靠转述下结论。

我在自己机器上测到了什么

侦探拿放大镜检查终端里的日志行,旁边贴着 18/sec、10 days、自动滚动三张便签
就查三件事:文件多大、写的什么、写得多快、会不会无限涨。

先看文件:

$ ls -lh ~/.codex/logs_2.sqlite*

logs_2.sqlite      126M
logs_2.sqlite-wal  4.9M
logs_2.sqlite-shm   32K

库里 66% 是 TRACE。内容不是业务日志,而是 websocket 轮询读写的底层打点:

$ sqlite3 ~/.codex/logs_2.sqlite "SELECT level,count(*) FROM logs GROUP BY level ORDER BY 2 DESC"

TRACE  65744      -- 占 66%
INFO   17968
DEBUG  13459
WARN    1974
ERROR      8      -- 当时合计约 9.9 万行

最新几条长这样:
TRACE  log  WouldBlock
TRACE  log  tokio-tungstenite/compat.rs:157 Read read -> poll_read
TRACE  codex_api::endpoint::responses_websocket  ...

只看当前行数还不够。这个库会边写边删,体积会把人骗过去。

在写的是桌面版,不是你敲的 CLI

原帖把问题说成"CLI 在写"。我查了日志里的 process_uuid,最近 500 行都来自同一个进程:

$ ps -p 2950 -o command

/Applications/Codex.app/Contents/Resources/codex app-server

写入来自 Codex 桌面版(Codex.app)的 app-server。当时我没有打开交互式 codex 终端。更准确的说法不是"CLI 在烧盘",而是"开着的 Codex 进程会写这个共享 SQLite 日志层",桌面版、TUI、编辑器扩展都可能参与。

文件只有 126 MB,但它 10 天写了 845 万行

主键是自增 id。我查了一下当前的 id 区间和实际行数:

$ sqlite3 ~/.codex/logs_2.sqlite "SELECT min(id), max(id), count(*) FROM logs"

min(id)   206,551,383
max(id)   215,003,791     -- 自增已到 2.15 亿
count(*)      101,406     -- 但只剩 10 万行

区间跨度 845 万,实际只剩 10 万  =>  835 万行已经被删掉了

这是"插入-修剪"循环:表里只保留最近约 10 天的行(我这边最老一行正好是 10 天前),旧行会被删掉。ls 看到文件稳定在 126 MB,不等于没写。自增 id 显示,10 天里实际插入了 845 万行,删掉了其中 835 万

这里推翻了我的第一版判断。我原本拿"残留的 10 万行"估算,得出"约 7 MB/天",还说这是标题党。按实际插入的 845 万行算,是 约 600 MB/天的日志正文,我少算了快 90 倍。这还只是逻辑写入;WAL、4 个索引、checkpoint、删除本身都会再写盘。

上游 issue 的量级更大:#17320 在流式输出时测到 WAL 写入 约 5–16 MiB/s,一次 50 token 回复让 MAX(id) 跳了约 5000 行;#28224 的报告者称 21 天写了约 37 TB,外推约 640 TB/年。我那次"6 秒只涨 109 行"的采样,只抓到了空闲时段;模型输出时才是高写入窗口。

"更新版本就好了"?没那么简单(2026-06-24 核实)

这句得拆开看。OpenAI 确实在 0.142.0(2026-06-22 发布)里合了两个降噪 PR(#29457 等),#28224 一度被关闭。但它很快又被重新打开(issue 的 state_reason 现在就是 reopened)——因为没修干净:macOS、Windows、Linux 上都有人报告升级到 0.142.0 后仍在持续写,有人用 iotop 实测 ~10 MB/s、约 315 TB/年

我自己这台也复现了。把 CLI 和桌面版核心都升到 0.142.0 之后,空闲仍 ~18 行/秒、流式输出时冲到上千,写的还是 TRACE/logTRACE/hyper_util 这些。为什么半截补丁不管用?OpenAI 在真正的修复 commit #29599 里自己写明了:

"0.142.0 的落盘过滤会禁用 target=log,但依赖库的日志记录是按它们原始的依赖 target 过滤的,等 tracing-log 把它们重贴成 target=log 之前就漏过去了——于是高频依赖 TRACE 继续进了 SQLite。"

这个完整修复 不在任何稳定版,只在 2026-06-24 才发的 0.143.0-alpha 里。截至本次核实,#28224#17320 都仍是 Open。所以准确的说法是:上游降了噪、完整修复在路上,但升级到当前最新稳定版还不能算修好。

到底是真是假

天平称量:TRUE 一侧很重,FALSE 一侧翘起,一个 FUD 印章正盖在 FALSE 那侧
机制是真的;"所有人一年烧光 SSD"这种说法过头了。

逐条对:

说法实测判定
偷偷往 logs_2.sqlite 真实存在,126 MB
写了"几万条"废话 低估了。10 天插入 845 万行,66% 是 websocket TRACE 真(还不止)
哪怕你什么都不干也在写 基本属实。我没开 CLI,后台桌面版 app-server 仍在写;只要有 Codex 进程开着,websocket 轮询就可能持续打 TRACE
文件看着没变大,底层却在狂写 正是病灶本身。滚动删除让体积稳定,物理写入没停
一年就把你的 SSD 烧光 看用量。重度用户要管;轻度用户没必要恐慌 夸大

病根在哪(lencx 翻的源码)

app-server 和 TUI 启动时都会挂一个 SQLite 日志层,默认过滤器是:

.with_filter(Targets::new().with_default(Level::TRACE))

也就是说,这个落盘 sink 默认接收 TRACE,而且有自己的过滤链,不受 RUST_LOG=warn 约束#17320 的报告者已经设了 RUST_LOG=warnlogs_2.sqlite 里仍然持续出现 TRACE。这个 issue 开于 2026-04-10,核对时仍是 Open。

SSD 风险要看写入量

SSD 的 TBW 是保修写入量,不是写到就坏的死亡线。风险取决于使用强度、盘容量和剩余空间:

  • 重度用户:像 #28224 那样 640 TB/年,落到一块焊死的 256 GB Mac SSD(标称约 150 TBW)上,几个月就超保修写入量。这种情况值得处理。
  • 轻度用户:写入量低一两个数量级,盘还能用很多年,没必要恐慌。

还有一个误解:它不会"烧穿同一小块"。SSD 有 FTL 和磨损均衡,写同一个文件名不等于反复擦同一批闪存单元。真正该看的是总主机写入量,以及磁盘太满时的写放大。

还有一层隐私风险容易被忽略:lencx 指出多个 issue 提到这个库可能落盘 websocket/SSE 的原始 payload,也就是可能夹带对话片段。所以别把 logs_2.sqlite 当成"无害缓存"随手上传、备份或公开。

我的结论:机制真实,上游有据,本机仍能复现;但它不是"人人一年烧光 SSD"。这取决于你开着哪些 Codex 进程、一天用多久、机器的 SSD 容量和剩余空间。我第一版只看残留行数,把它判成 FUD,是错的。

怎么办

扫帚把 126MB 的大盒子扫成 5MB 的小盒子,旁边的 SSD 笑着竖大拇指
清理能回收体积,但拦不住它继续写。两件事要分开做。

下面这些大多来自 lencx 的复盘,我在本机核对过。动手前先完全退出 Codex,否则会踩 #22444 的句柄问题:进程还占着已删除的 WAL,du 看着降了,df 却不释放空间。

先确认没进程占用

pgrep -fl 'Codex|codex|app-server'
lsof -nP | grep -E '\.codex/.+logs_2\.sqlite'

清理回收体积(治标)

# 确认 Codex 已退出后
sqlite3 ~/.codex/logs_2.sqlite 'DELETE FROM logs; VACUUM;'

这能把文件从 126 MB 缩回几 MB,但拦不住它重新开始写。清理 ≠ 限流。

临时止血:拦住新写入(治标,但管用)

sqlite3 ~/.codex/logs_2.sqlite \
  "CREATE TRIGGER IF NOT EXISTS block_log_inserts
   BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END;"

# 回滚
sqlite3 ~/.codex/logs_2.sqlite "DROP TRIGGER IF EXISTS block_log_inserts;"

触发器会忽略所有插入,效果直接。代价是 feedback_log_body 会变空,报 bug 时缺诊断附件;升级若重建表,触发器可能被删,升级后要复查。

把数据库挪到别的盘(权宜方案)

# ~/.codex/config.toml
sqlite_home = "/Volumes/ExternalDisk/codex-sqlite"
# 或临时: CODEX_SQLITE_HOME=/Volumes/ExternalDisk/codex-sqlite codex

这比软链单个文件干净,但只是搬走写入,不会减少写入。外置盘断开或休眠会影响 Codex。注意它迁的是整个 SQLite home,state、logs、goals、memories 都会跟着走。

三个别踩的坑

  • /tmp 软链在 macOS 没用:macOS 的 /tmp 指向 /private/tmp,在 APFS 系统盘上,不是内存盘。软链过去只是从 SSD 一个目录挪到另一个目录,对写入毫无帮助。readlink /tmp; mount | grep -i tmpfs 自己验。
  • RUST_LOG=warn 管不住这个 sink:它能压低 stderr,但这个 SQLite 落盘层有独立过滤链(见 #17320)。
  • [feedback] enabled = false 不是开关:它只关反馈提交流程,启动时照样挂日志层。

顺手:备份排除 WAL/SHM

--exclude='*.sqlite-wal'
--exclude='*.sqlite-shm'

WAL 和 SHM 是运行时文件,几十 GB 同步到另一台机器多半只是在复制问题。

上游还要继续收口

这些都只是止血。Codex 需要继续收窄落盘 sink 的默认级别,不默认落 websocket 原始 payload,给 WAL 和总大小加上限,并提供明确开关(比如 sqlite_log_level)。#28224 已因降噪 PR 关闭,但 #17320、#22444、#24275、#28997 核对时仍是 Open。


自己花一分钟判断该不该管:ls -lh ~/.codex/logs_2.sqlite* 看体积,再跑一次 SELECT max(id),count(*) FROM logs。如果 max(id) 是几千万上亿、行数却只有十几万,你这台机器也在"写了删、删了写"。重度用、又是焊死 SSD 的 Mac,建议处理;偶尔用用,知道有这回事即可。

本文数据均在作者本机 ~/.codex/ 实测(codex-cli 0.134.0),终端输出未经修饰。源码定位、偏方复盘与上游量级数据来自 lencx(浮之静)《Codex 日志正在燃烧你的 SSD》,本文在自己机器上做了独立复现验证。插图由 ChatGPT 生成。

参考 issues(2026-06-23 核对):

  • #17320 — TRACE 日志无视 RUST_LOG,流式输出时大量写 WAL
  • #28224 — 21 天约 37 TB、外推约 640 TB/年;2026-06-22 因降噪 PR 合并关闭
  • #22444 — WAL 删除后空间不释放(进程仍持有句柄)
  • #24275 · #28997 — 正常使用下 WAL 增长到数十 GB
下一篇 →
你没法单独 import 一个 GSI

评论

评论发布后会立即公开,如触发规则可能被审核下架。

最多 1000 字。