先别急着卸载 AiCoding。如果你是因为“电脑磁盘占用 100%”搜到这篇文章,大概率和我前天遇到的情况一样:Windows 任务管理器里磁盘那一栏长时间满格,后台挂着 AiCoding 就开始卡,退出浏览器、关掉微信也没用。我花了小半天追根溯源,最后发现罪魁祸首不是软件本身,而是它自带的 PostgreSQL 实例——准确说是 pg_wal,也就是很多人网上常说的 wal-data 目录里,堆了几十甚至上百 GB 的 WAL 日志。今天把这套排查链路完整写下来,给所有用 AiCoding 或其他本地 AI 编程工具的朋友一个参考。
先说结论:AiCoding 这类 AI 编程助手,为了做代码语义检索、对话历史和本地任务缓存,会在你电脑上跑一个完整的 PostgreSQL 数据库。PostgreSQL 为了保证崩溃恢复,会把所有事务先写入 WAL(预写日志),再写数据文件。正常情况下这些日志会被 checkpoint 自动回收,但如果数据库配置被改坏、复制槽没人消费、归档命令失败,WAL 就会只增不减,直到把整个磁盘吃满。这篇文章会带你从症状开始,一层层挖到根因,再给出可直接照抄的清理和预防方案。
1. 事故现场:任务管理器里的 100% 和躲在用户目录里的 PostgreSQL
1.1 症状清单:不是 CPU,不是内存,是磁盘
那天我的电脑表现很典型:开机两小时,没跑编译、没开虚拟机,只是开着 AiCoding 和一个编辑器,系统就越来越慢。打开任务管理器,CPU 和内存都只有 30% 左右,磁盘那一栏却顶在 100% 不动。点开“进程”标签页按磁盘排序,排在最前面的是几个不认识的后台进程,名字类似 postgres.exe,磁盘读写每秒几十 MB 到上百 MB。
这时候我几乎可以确定:这不是 Windows 更新抽风,也不是普通后台软件中转,而是某个会持续写数据的本地服务出了问题。再一看 C 盘剩余空间,从几天前的 80GB 掉到了 700MB。系统盘直接爆掉,这才会导致鼠标漂移、资源管理器无响应、各种程序报“磁盘空间不足”。
很多人遇到这个情况第一反应是卸载 AiCoding,但我想提醒一句:卸载不一定删掉本地数据库,反而可能把你积累的向量索引和对话历史一起清掉。更合理的顺序是先定位大目录,确认是不是 PostgreSQL 的 WAL 文件,再决定怎么处理。
1.2 定位目录:用 WizTree 和 PowerShell 找到占空间的元凶
Windows 上查磁盘占用,我一般不用系统自带的“存储设置”,那玩意儿扫描太慢,而且不显示文件级明细。这里推荐两个工具:
- WizTree:扫描速度极快,几秒钟就能把整个分区的文件大小按目录列出来,适合先看全局。
- PowerShell:适合自己做巡检脚本,虽然全目录递归慢,但可以精确统计指定目录。
我用 WizTree 扫了 C 盘,排在第一的是一个名字带 .aicoding 的目录,下面有个 data 子目录,占了将近 300GB。展开之后,最夸张的是 data\postgresql\pg_wal 或者叫 wal-data 的文件夹,里面全是 00000001000000XX000000XX 这种格式的文件,单个 16MB,密密麻麻几千个。
如果你不看 GUI 工具,也可以直接用 PowerShell 统计目录大小,命令大致如下:
powershell复制$path = "C:\Users\你的用户名\.aicoding"
Get-ChildItem $path -Directory -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum
[PSCustomObject]@{
Path = $_.FullName
SizeMB = [math]::Round($size / 1MB, 2)
}
} | Sort-Object SizeMB -Descending | Select-Object -First 20
macOS 或 Linux 上更简单:
bash复制du -sh ~/.aicoding/*
du -sh ~/.aicoding/data/postgresql/pg_wal/* | tail -5
看到 pg_wal 这个目录名,事情就已经清楚了八九成。接下来要回答的问题是:它为什么会长这么大?
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. WAL 不是日志洪水:为什么 AiCoding 的本地数据库会吃掉 300GB
2.1 AiCoding 本地 PostgreSQL 到底在存什么
在很多人的认知里,AI 编程工具就是把代码发到云端,然后拿结果回来。但实际上,AiCoding 的本地端需要做很多事情:
- 扫描本地项目,把代码文件切块后喂给 embedding 模型,生成向量并存入本地向量数据库;
- 保存你和 AI 的会话历史,方便跨会话召回;
- 缓存代码补全、重构建议等中间结果;
- 记录文件变更、任务执行状态,支持增量索引。
这些数据用 SQLite 也能存,但向量检索、全文检索、复杂查询、并发写入这些需求,用 PostgreSQL 加 pgvector 扩展会更顺手。所以 AiCoding 选择在本地内置一个 PostgreSQL 实例,这本身不是设计缺陷,数据库落地用户目录也是常见做法,问题只在于这个实例的运维参数没有针对个人电脑优化。
2.2 WAL 是什么:先写日志,再写数据的崩溃恢复机制
PostgreSQL 的 WAL(Write-Ahead Log)翻译成“预写日志”。它遵循一个非常朴素的原则:在修改任何数据文件之前,先把修改动作本身追加到日志文件里。
类比一下,就像你记账时会先写流水账,再更新分类账本。万一账本撕了,只要有流水账,就能恢复到最后一笔交易。PostgreSQL 每次 INSERT、UPDATE、DELETE,第一步都是写 WAL,然后才改数据缓冲区;数据缓冲区攒到一定程度,再由后台进程刷到磁盘上的真实数据文件。
WAL 文件默认每个 16MB,存放在数据目录下的 pg_wal 文件夹里(PostgreSQL 10 以前叫 pg_xlog,AiCoding 各版本用的数据库版本不同,目录名可能不一样,这也是网上有人叫它 wal-data 的原因)。
2.3 正常情况下 WAL 为什么不会无限膨胀
WAL 文件不是只增不减的。PostgreSQL 里有一个核心机制叫 checkpoint(检查点)。每隔一段时间,或者当 WAL 总量达到一定阈值时,后台检查点进程会把所有脏数据页刷到磁盘,并更新控制文件里记录的检查点位置。一旦检查点完成,检查点之前的 WAL 文件就失去了崩溃恢复价值,可以被回收复用或删除。
控制这个行为的关键参数是 max_wal_size。它是个软上限:当 WAL 总大小接近这个值时,系统会主动触发检查点,然后清理掉无用的 WAL。个人电脑上默认通常是 1GB 到 4GB,也就是说,只要配置正常,你的 pg_wal 目录撑死也就几个 GB,绝无可能涨到 300GB。
那为什么会在 AiCoding 的本地数据库里失控?常见原因就三类:
- 归档模式开了,但归档命令失败:只要
archive_mode=on,WAL 在被清理前必须等归档进程成功归档。如果归档目标目录不存在、路径写错、命令报错,WAL 就会全部积压。 - 复制槽没人消费:复制槽是 PostgreSQL 主从同步的机制。如果客户端消费 WAL 的进度停住了,数据库会保留从这个进度开始的所有 WAL,防止从库追不上。AiCoding 某些版本初始化数据库时可能创建过复制槽,但组件升级后这个槽成了僵尸槽。
wal_keep_size或wal_keep_segments设置过大:这是另一个“人为保留”指令,告诉数据库额外保留多少 WAL,避免从库短暂断开后跟不上。设得太大,本地单机场景就是纯浪费。
所以,我们真正要做的不是手动删文件,而是找到这三类问题里究竟是哪一个,把根因处理掉。手动删 WAL 文件就像把垃圾桶踢到床底,治标不治本。
3. 一个复制槽和一个失败归档命令:我的根因定位全过程
3.1 连接实例:在不知道密码时怎么拿到 psql
要查 PostgreSQL 内部情况,得先连上它。AiCoding 自带的 PostgreSQL 通常监听在 127.0.0.1 的某个非默认端口上,比如 55432、54329 这种,也可能复用 5432。如果你不知道端口和密码,有几个办法:
- 看 AiCoding 的设置界面,高级选项里可能有“本地数据库端口”或“数据目录”;
- 打开任务管理器,右键
postgres.exe,在“命令行”里能看到-p 端口和-D 数据目录; - 到数据目录下找
postgresql.conf,里面port参数写得很清楚。
连接时可以直接用自带的 psql。先找到 psql 路径,比如 C:\Users\你的用户名\.aicoding\pgsql\bin\psql.exe,然后执行:
bash复制"C:\Users\你的用户名\.aicoding\pgsql\bin\psql.exe" -h 127.0.0.1 -p 端口 -U postgres -d postgres
如果提示需要密码,先在 pg_hba.conf 里看认证方式是不是 trust。本地工具默认通常是 trust,不需要密码。如果真需要密码,去 AiCoding 的日志目录里找初始化时打印的数据库账号信息,或者翻它的安装脚本。
3.2 第一组 SQL:WAL 目录的真实大小和保留原因
连接成功后,先看 WAL 目录到底有多占空间:
sql复制SELECT pg_size_pretty(sum(size)) AS wal_total_size
FROM pg_ls_waldir();
我这边执行完返回的结果是 278 GB。接着看关键配置:
sql复制SHOW max_wal_size;
SHOW checkpoint_timeout;
SHOW archive_mode;
SHOW archive_command;
SHOW wal_keep_size;
返回结果让我有点意外:
| 参数 | 值 | 说明 |
|---|---|---|
max_wal_size |
2GB | 软上限正常 |
checkpoint_timeout |
5min | 触发方式正常 |
archive_mode |
on | 有归档 |
archive_command |
copy "%p" "C:\\Program Files\\AiCoding\\archive\\%f" |
目标目录不存在 |
wal_keep_size |
0 | 没额外保留 |
archive_mode=on 这条已经够可疑了。再查一下复制槽:
sql复制SELECT slot_name, slot_type, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag_bytes
FROM pg_replication_slots;
结果有一行物理复制槽,active 是 f,restart_lsn 停在一个很老的位置。这个 WAL 延迟换算出来大约有 270GB。两个元凶同时出现了。
3.3 元凶一:一个没人消费的物理复制槽
复制槽是 PostgreSQL 里一个很好用但也很容易造出“存储黑洞”的功能。正常情况下,主库向从库同步时,从库会持续告诉主库“我已经消费到某个 LSN 了”。只要这个进度持续往前跑,主库就可以清理掉旧 WAL。
但如果从库挂了、断了,或者干脆只是初始化时创建了复制槽,后面从来没连过,那么这个槽的 restart_lsn 就永远卡在原地。PostgreSQL 为了保护从库,不会删掉从 restart_lsn 到当前写入位置之间的任何 WAL。时间一长,这些 WAL 就会把所有可用磁盘空间填满。
AiCoding 的本地实例为什么会有物理复制槽?最可能是某个历史版本用它做多设备同步或本地备份,后来功能下线了,槽却留了下来。这种情况在不少带内置数据库的桌面软件里都出现过。
3.4 元凶二:archive_mode 开着,归档目标却不存在
再来看归档。archive_mode=on 之后,PostgreSQL 的归档进程会在 WAL 文件不需要之前把它复制到归档目录,确认复制成功后才允许系统清理该 WAL。问题在于,我指定的归档目标目录 C:\Program Files\AiCoding\archive 压根就不存在,而且 Program Files 目录普通权限根本写不进去。
于是出现了一个死循环:
- 归档命令每次执行都失败;
- PostgreSQL 认为 WAL 还没归档成功,不能清理;
- 新的 WAL 还在不断产生;
- 磁盘被越堆越满。
这里我踩过一个坑:只删复制槽,没有关 archive_mode,重启后 WAL 还是在涨。因为归档命令失败的问题还挂在那边,PostgreSQL 依然保留所有未归档 WAL。所以这两件事必须一起处理。
4. 清理与修复:从释放磁盘到重建向量索引的完整操作
4.1 操作前必须做的三件事
正式动手清理之前,我建议你依次做这三件事,缺一不可:
- 第一,正常退出 AiCoding,确认托盘图标消失,进程列表里没有 ai-coding 相关主进程。但要注意,仅仅退出主程序,
postgres.exe可能还留在后台,需要到任务管理器里手动结束,或者用命令行taskkill /IM postgres.exe /F(这是最后手段,优先干净退出)。 - 第二,备份配置文件:把数据目录下的
postgresql.conf和pg_hba.conf复制到桌面。后面改参数时改错了能回滚。 - 第三,评估数据价值:问自己一个问题,如果本地向量索引全部重建,损失能不能接受?能接受,方案 B 最省事;不能接受,老老实实走方案 A。
4.2 方案 A:进入数据库清理 WAL 并修复配置
这个方案保留 AiCoding 的索引和对话数据,只清理 WAL,并修好根因。
首先,在 psql 里执行强制检查点:
sql复制CHECKPOINT;
这个命令会立刻刷新所有脏数据页,并尝试清理无用的 WAL。执行之后再查一次:
sql复制SELECT pg_size_pretty(sum(size)) AS wal_total_size
FROM pg_ls_waldir();
如果空间没变小多少,说明有东西在挡着清理。那就先处理复制槽。执行前再确认一次当前库没有其他实例依赖它:
sql复制SELECT slot_name, active, restart_lsn FROM pg_replication_slots;
确认是僵尸槽之后,删除它:
sql复制SELECT pg_drop_replication_slot('槽名称');
然后再执行一次 CHECKPOINT;,这个时候 pg_ls_waldir() 的总大小一般会断崖式下跌。
接着处理归档问题。对于个人电脑上的 AiCoding,归档基本没有意义,最省事的方式就是关掉它。修改 postgresql.conf:
ini复制archive_mode = off
archive_command = ''
如果不想关归档,就把归档目录改成真实存在的路径,并且确保当前用户有写权限。但说实话,本地单机数据库开归档没有收益,建议直接关。
改完配置后重启 PostgreSQL 服务。重启方式可以再退出 AiCoding 后单独启动它,也可以用工具的修复命令。关键是重启后验证:
sql复制SHOW archive_mode;
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
正常情况,WAL 总量会掉到几 GB 以内。
4.3 方案 B:数据目录整体重置
如果你连 psql 都连不上,或者 WAL 已经把系统盘占满到无法启动服务,那就不必执着于内部清理。AiCoding 的本地索引目录本身是可重建的,它和源码、云端账号信息是两回事。
操作方法是:
- 退出 AiCoding;
- 把它数据目录下的
data文件夹改名,比如改成data-bak-时间戳,不要直接删除,给自己留一条后路; - 启动 AiCoding,软件检测不到数据库会重新初始化一个全新的实例;
- 确认启动正常后,进入软件重新添加项目、触发代码索引,向量和对话记录会慢慢重建。
这个方案最大的优点是不需要处理数据库内部细节,对新手友好;缺点是项目越大,重建索引耗时越长,而且之前的本地会话记录会丢。如果项目几个 GB,大概要重新索引几十分钟到几个小时,看机器性能。
4.4 清理之后的验证与索引重建
不管用哪个方案,清理完 WAL 之后还有两件事要做。
第一,重建向量索引。 长期 WAL 暴涨期间,数据库多处表可能膨胀,特别是向量表。可以先用 SQL 做一次清理和重建:
sql复制VACUUM (VERBOSE, ANALYZE);
REINDEX DATABASE postgres;
如果 AiCoding 使用的数据库名不叫 postgres,换成实际的库名。这一步需要一点时间,但能显著改善后续检索性能。
第二,确认磁盘占用回到正常范围。 我用 WizTree 又扫了一遍,pg_wal 目录从 278GB 降到了 1.6GB,C 盘可用空间回到 80GB 以上,磁盘 100% 的现象当场消失。然后重新打开一个项目,让 AiCoding 跑一次索引,确认代码补全和问答功能都正常。
5. 长期预防:给 AiCoding 的本地数据库立规矩
5.1 配置文件里的底线参数
经历过一次磁盘爆满之后,我把 postgresql.conf 里下面这几个参数固定了下来。它们是我的底线,推荐有类似问题的读者也照这个思路改。
| 参数 | 建议值 | 为什么 |
|---|---|---|
max_wal_size |
2GB | WAL 积压上限,防止异常时直接吃满磁盘 |
min_wal_size |
128MB | 保留最小 WAL 池,避免频繁创建文件 |
checkpoint_timeout |
15min | 即使 WAL 没到上限,也定期强制检查点 |
archive_mode |
off | 本地单机不需要归档 |
wal_keep_size |
0 | 不额外保留 WAL |
max_slot_wal_keep_size |
1GB | 限制复制槽能占用的最大 WAL 空间 |
autovacuum |
on | 防止脏数据堆积导致索引膨胀 |
其中 max_slot_wal_keep_size 是 PostgreSQL 13 以后的参数,如果你的版本支持,一定要设。它相当于给复制槽上了个“消费额度”,即使某个槽出了故障,它最多也只能拖住 1GB WAL,不至于再把磁盘吃爆。
5.2 每天 30 秒的磁盘自查习惯
修好了不等于以后不出事。我给自己的 Windows 加了一个计划任务,每天早上开机后跑一条 PowerShell 命令,检查 C 盘剩余空间,如果低于 20GB 就弹窗提醒。
powershell复制$disk = Get-PSDrive C
$freeGB = [math]::Round($disk.Free / 1GB, 1)
if ($freeGB -lt 20) {
Write-Host "C盘剩余空间不足: $freeGB GB" -ForegroundColor Red
}
另外每个月用 WizTree 扫一次 C 盘,主要看 .aicoding 目录有没有异常增长。如果发现 pg_wal 超过 5GB,就直接打开数据库执行:
sql复制SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
SELECT slot_name, active FROM pg_replication_slots;
这两句 SQL 能在一分钟内判断问题属于“正常波动”还是“复制槽/归档故障”。
5.3 给杀毒软件和索引任务画边界
还有一个经常被忽略的帮凶:Windows Defender 或其他杀毒软件。PostgreSQL 运行时会高频读写大量 WAL 文件,杀毒软件如果实时扫描数据目录,就会产生两倍甚至三倍的磁盘 IO,让本来不重的负载看起来像磁盘 100%。而且杀毒软件在扫描时可能短暂占用文件句柄,导致 PostgreSQL 清理 WAL 的进程受阻。
建议在 Windows 安全中心里,把 AiCoding 的数据目录加入排除列表。注意,这是把双刃剑:排除目录意味着杀毒软件不再扫描该目录下的文件,所以前提是你确信 AiCoding 本地数据库的二进制来源可靠。我个人的做法是只排除 data 文件夹,不排除程序安装目录。
最后说个小技巧:AiCoding 这类工具在“后台索引整个磁盘”的时候最容易制造大量 WAL。如果你和我一样电脑上项目多,建议在工具的索引设置里,只勾选经常用到的项目目录,别让它全盘扫描。还有,长期不用的项目该删索引就删索引,重建最多花几十分钟,但攒着不动会在某一天给你惊喜。
磁盘 100% 的排查有时候看起来很吓人,但只要理解 PostgreSQL 的 WAL 回收机制,再顺着复制槽、归档命令、杀毒软件这几个方向查,基本都能在半天内解决。希望这篇复盘能帮你少走一点弯路。
