前几天早上我刚打开电脑,微信就开始弹“存储空间不足”,我心想坏了。一看C盘,剩余空间不到300MB,系统分区直接红得发黑。这种时候最容易干蠢事——打开各种“清理大师”一键狂删,或者对着C盘目录瞎猜,删了不该删的,把软件搞坏。这次我没急着动手,而是让 Codex 来帮我做了一次完整的磁盘体检。最终我定位到 AppData 目录占了 87.81GB,并且在没有误伤任何软件配置的前提下,安全释放了大约60GB的空间。
这篇文章就是这次排查的全过程记录。我会把 AppData 为什么会膨胀到这种程度、我为什么用 Codex 而不是传统扫描工具、具体的排查命令和判断逻辑,以及最后的删与不删、如何防止下次再爆红,一条条讲清楚。适合C盘常年告急、又不敢乱动文件的人,尤其是装了各种开发工具、浏览器、虚拟机的人。
1. AppData 这个“黑洞”为什么能吞下 87.81GB
1.1 先搞清楚 AppData 到底是什么
AppData 是 Windows 给每个用户单独划分的一块应用程序数据目录,默认是隐藏的。你在资源管理器地址栏输入%LOCALAPPDATA%、%APPDATA%就能看到它。它下面有三个子目录,分工完全不同:
Local:本机专属的重缓存数据,比如下载缓存、临时文件、软件更新包、虚拟磁盘文件都在这。这是膨胀的主力,空间占用通常最大。Roaming:可以跟着账户漫游的数据,主要是各种软件的配置、登录态、历史记录。看起来不大,但日积月累也很可观。LocalLow:低权限进程用的数据区域,浏览器插件、某些游戏组件会写在这里,一般占不了太大空间。
如果用生活化的类比,AppData 不是“垃圾场”,更像是家里那个杂物间:里面有日常要用的工具箱,也有积压很久的快递纸箱。你看着乱,但不能因为乱就全扔,得先分清哪个是能重建的缓存、哪个是不可重建的配置。
很多人一看C盘满了就冲进 AppData 乱删,结果最常见的两种悲剧:一是把软件配置删了,软件打开跟新装的一样,登录态全丢;二是删掉了正在被占用的文件,导致软件崩溃甚至系统组件异常。所以我一直坚持的原则是:先定位,再判断,最后动手。
1.2 空间守恒:凡是缓存,必有来源
我特别喜欢一个说法:磁盘空间是守恒的,每个大文件都有它的“生产者”。如果能回答“谁创建了它”,基本就能回答“能不能删它”——因为缓存类的东西删了会自动重建,配置类的东西删了就真没了。
87.81GB 这种量级的 AppData,通常不是某一个大文件单独造成的,而是好几个“大户”联手。我自己这次最典型的构成大概是这样的:
| 目录 | 典型占用范围 | 来源 |
|---|---|---|
| WSL2 的 ext4.vhdx 虚拟磁盘 | 10~60GB | Linux 子系统里的软件包、日志、容器镜像 |
| 包管理器缓存(npm/pnpm/pip/Yarn) | 3~30GB | 下载过的依赖包压缩文件,用于离线加速安装 |
| Temp 临时目录 | 2~15GB | 软件安装包、解压临时文件、崩溃转储 |
| 浏览器用户数据与缓存 | 3~20GB | 网页缓存、Cookie、扩展、媒体文件 |
| 显卡着色器缓存(DXCache/GLCache) | 1~8GB | 游戏和图形程序运行时生成的着色器汇编结果 |
| Electron 应用的逐个项目缓存 | 1~5GB | 聊天软件、文档工具等基于 Electron 的软件自带一个浏览器内核 |
这里要特别说一下 WSL2。如果你装了 Windows 的 Linux 子系统,整个 Linux 文件系统其实被塞进一个叫ext4.vhdx的虚拟磁盘文件里,位置就在%LOCALAPPDATA%\Packages\...\LocalState下。这个文件很特殊:你在 Linux 里删了文件、卸载了软件包,空间并不会自动还给Windows。因为 ext4 文件系统删除数据后,虚拟磁盘内部腾出了空间,但 vhdx 文件本身不会主动收缩,除非你显式压缩。这就是很多人明明清理了 Linux 却发现C盘丝毫没变的原因。
1.3 87.81GB 这个数字具体是怎么分布的
回到我这次的情况。我让 Codex 跑完统计后,结果大概是这样的:WSL2 的虚拟磁盘约 38GB,npm 缓存约 13GB,pip 缓存约 8GB,Temp 目录约 9GB,浏览器缓存约 6GB,剩下的零头分散在显卡着色器缓存、更新备份等地方。加起来差不多就是 87.81GB。
这个报告其实解决了我最大的疑问——为什么我之前用各种清理工具“扫”不出东西。因为大部分清理工具只会盯系统临时文件和安全软件定义的“垃圾”,它们根本不理解 npm 缓存、WSL 虚拟磁盘这种东西的存在。它们没做错,只是规则覆盖不到这里。
1.4 为什么 Windows 自带的清理工具常常无能为力
Windows 的磁盘清理(cleanmgr)和存储感知,扫出来的大头通常只有“系统更新备份”“临时文件”“回收站”。但 87.81GB 的 AppData 里,真正的大头是开发链路的缓存和虚拟磁盘,这些在系统自带的清理规则里根本不会主动处理。
系统自带工具的逻辑是“保守优先”:不确定能删的就不删,绝不冒风险。这对普通用户是好事,但对我们这种C盘已经被开发环境占满的人来说,光靠它是不够的。你需要的是一个“能看明白每个目录是什么、有问题还能继续追问”的工具,这正是我这次用 Codex 的原因。
2. 为什么我选择让 Codex 来排查,而不是直接用 SpaceSniffer
2.1 传统磁盘扫描工具的三种不足
我以前也用过 SpaceSniffer、WinDirStat 这类可视化工具,方格图一出来确实震撼,但深入用就会发现三个痛点:
- 能看大小,不能解释用途。它给你一个超大目录的名字,但不会告诉你“这是 npm 的缓存,删了会自动重建”“这是 WSL 的磁盘,删了系统就废了”。你得自己去搜,挨个目录查,非常费劲。
- 交互是一次性的。扫描完、看完图,对话就结束了。如果你想看某个子目录再往下钻、或者对比两个目录的差异,又要重新扫一遍。
- 遇到权限拒绝和隐藏目录,给出的上下文很少。扫到一半报错,你甚至不知道是卡住了还是正常。
不是说这些工具不行,它们依然有快速建立全貌的价值。但如果目标是“不仅查出谁大,还想知道能不能删、为什么能这么删”,传统工具就给不了答案了。
2.2 Codex 在这个场景里的定位
Codex 是一款可以跑在终端里的 AI 编程助手,但我不把它当“写代码工具”用,而是当“能执行命令的排查助手”。它能读取本地文件、执行 PowerShell 命令、看命令输出,再基于这些结果继续推理。关键是,它可以对话式地持续追踪一个问题,不需要我手动把上一轮的结果复制粘贴给下一轮。
在这次磁盘排查中,Codex 实际上帮我做了三件事:
- 第一,根据我“统计某个目录下各子目录大小”的需求,生成并执行正确的 PowerShell 脚本;
- 第二,把脚本输出整理成排序表,筛出 TOP 级别的占用目录;
- 第三,针对每个可疑目录,解释它的用途、判断删除风险,给出“能删/谨慎删/别删”的建议。
这件事用传统方案不是做不到,而是要把“写脚本、跑脚本、查资料、汇总判断”四步都自己做。Codex 的价值不是取代前三步,而是把每一步之间的衔接成本大幅压下来。
2.3 用 Codex 排查前的准备和边界设定
我这次的操作环境是:Windows 11 系统,装有 Node.js LTS 版本。如果之前没装过 Codex,一条命令就能装好,然后在终端里完成登录和权限配置就能开始。我建议第一次使用就给它定好“工作边界”,我的原话大概是:
当前目标:排查C盘空间占用。请你只做只读分析和命令执行,不要修改文件;如果要删除或移动任何文件,先告诉我,等我确认后再执行。
这句话非常关键。AI 助手不是不能执行危险命令,但你必须把它限定在“可审计”的范围内。排查阶段它只负责读取和统计,不负责处置;处置阶段每一步都先出方案、等我确认。这样就算中间出了什么意外,我也知道回滚的口子在哪。
2.4 为什么“对话式排查”比“一把梭翻记录”更合适
磁盘排查和写业务代码不一样,它不是一次性能定义完需求的工作。通常过程是这样的:看到第一层结果,才知道第二层该查哪里;看到第二层结果,才知道哪些目录值得深挖。这本质上是一个迭代式的决策链。
手工做的话,最耗时的环节就是反复写 PowerShell 统计脚本。命令不难,但每个目录层级都要调整路径、注意排除符号链接、处理权限错误,来回折腾半小时很正常。而 Codex 能记住上下文,它上一轮已经知道了 C 盘顶层有哪些目录、每个目录多大,我只需要说“再往 AppData\Local 下面钻一层”,它就能基于已有信息继续跑,不需要我重新描述一遍背景。
3. 完整排查实录:从 C 盘全貌到揪出 87.81GB
3.1 第一步:让 Codex 输出 C 盘顶层目录占用排行
排查开始时,我并没有直接指定 AppData。我先让它统计当前用户目录下一级各文件夹的大小,这样能对全局有个感知。
Codex 生成的 PowerShell 脚本大致长这样:
$path = "C:\Users\MyName" Get-ChildItem -Force $path -Directory | ForEach-Object { $size = (Get-ChildItem $_.FullName -Recurse -Force -File -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum [PSCustomObject]@{ Path = $_.FullName SizeGB = [math]::Round($size / 1GB, 2) } } | Sort-Object SizeGB -Descending | Format-Table -AutoSize这条命令的本质是:遍历指定目录下的每个子文件夹,递归统计里面所有文件的大小总和。跑完后结果很清晰,AppData 以 87.81GB 遥遥领先,排在第二的是用户目录下的另一个数据文件夹,只有几个 GB。也就是从这一刻起,主战场被锁定在了 AppData。
这里有个细节值得说:这个统计脚本对大目录会跑得比较慢,尤其是 AppData 这种十几万个文件的目录。我当时的做法是先跑完这一层拿到“嫌疑人名单”,而不是一上来就做全盘扫描,否则光是统计就要浪费大把时间。
3.2 第二步:顺着 AppData 逐级下钻,找出“罪魁祸首”
锁定 AppData 后,我让 Codex 先分别统计Local、Roaming、LocalLow三个子目录的大小。结果很典型:Local占了约 66GB,Roaming占了约 20GB,LocalLow只有零星几个 GB。这意味着大头都在本机专属缓存区域。
继续下钻Local,逐级统计后,TOP 列表大概长这样:
| 目录 | 占用 |
|---|---|
| Packages 下的 WSL2 虚拟磁盘 | 约 38GB |
| npm-cache | 约 13GB |
| Temp | 约 9GB |
| pip 缓存 | 约 8GB |
| 浏览器用户数据(缓存部分) | 约 6GB |
| 显卡着色器缓存 | 约 4GB |
到这一步,“87.81GB 是怎么构成的”已经非常清晰了。接下来的问题就是:这些目录分别是什么、能不能删、删除后有什么后果。这一步才是 Codex 区别于普通扫描工具的核心价值所在。
3.3 第三步:追问 Codex“这是什么、能删吗”
我的常用追问句式是:
每个目录帮我解释一下用途。按你的判断,哪些是可安全清理的?哪些需要谨慎?哪些绝对不能动?请给出依据。
Codex 会结合 Windows 目录约定和命令输出结果,逐项给结论。我印象比较深的几个判断:
npm-cache存的是 npm 下载过的依赖压缩包,作用是加速后续安装。删除不会影响已安装的依赖,只是下次安装依赖时需要重新下载,速度会略慢。pip cache同理,Python 包管理器下载的 wheel 包缓存,删了安全。Temp目录里大部分是软件安装和解压过程留下的临时文件,清理时最好先退出正在运行的程序,否则可能提示文件被占用。- WSL2 的 ext4.vhdx 是 Linux 文件系统的载体,绝对不能直接删,需要在 WSL 关闭后做压缩操作。
Roaming下大部分是软件配置和登录态,属于“不能乱动”的类型,我只做统计,不主动清理。
这些判断如果你自己去查,也能查到,但每个目录都要去搜一圈,时间成本太高。Codex 最大的帮助是把“判断链路”直接摆在面前,我只需要最后决定“执行还是不执行”。
3.4 过程中踩过的几个坑
排查过程不是一帆风顺的,有些问题现在想来很有代表性:
第一个坑是符号链接导致的重复统计。用户目录下存在不少目录联接(junction),比如某些开发工具会把数据目录软链到其他地方。如果没有跳过符号链接,脚本可能顺着链接跑到别的盘去统计,或者把同一个文件算两遍,出来的数字就很离谱。后来我让 Codex 在统计脚本里加入对ReparsePoint属性的过滤,结果才正常。
第二个坑是“拒绝访问”报错。AppData 下也有少数系统受保护的文件,统计过程中会抛错。如果不做错误静默处理,脚本跑到一半就中断了,后面全部白跑。所以脚本里的-ErrorAction SilentlyContinue不是偷懒,是必要防御。
第三个坑是深目录扫描耗时长。我的第一次全量统计跑了接近十分钟,而且 PowerShell 单线程递归大目录确实会让人怀疑“是不是卡住了”。后来我调整为“先统计一层子目录,再针对可疑目录单独下钻”,效率高很多。这个思维同样适用于你手动排查的场景。
4. 锁定目标后的删与不删,我给出的完整处置清单
4.1 先把目录分成三档:可删、谨慎删、别删
排查完之后,最重要的就是处置。我按照 Codex 给出的解读,把目录分成了三档:
| 分类 | 代表目录 | 处理方式 |
|---|---|---|
| 放心删 | Temp 临时文件、npm/pnpm/pip 缓存、显卡着色器缓存、缩略图缓存 | 删除后可自动重建,无副作用 |
| 谨慎删 | 浏览器缓存、编辑器索引缓存、软件更新包残留 | 删除后软件会重建缓存,但可能丢失登录态或需重新索引 |
| 别删 | Roaming 下的软件配置、WSL2 的 vhdx 实体、正在使用中的软件数据 | 误删后轻则重新配置,重则软件崩溃、子系统损坏 |
这个分类不是拍脑袋定的,核心逻辑就是我前面说的“生产者原则”:凡是系统或软件能自动重建的,都是“放心删”;凡是重建成本高、或者本来就是唯一副本的,就归入“别删”。
4.2 WSL2 虚拟磁盘这种“大头”的标准处理方式
WSL2 的 ext4.vhdx 是我这次最大的单个占用源,也是很多人最容易误操作的目录。如果你直接把这个文件删了,你的整个 Linux 子系统相当于被格式化,所有数据、配置、安装过的软件全部没了。所以正确做法不是“删”,而是“压缩”。
标准流程是这样的:
# 第一步:关闭所有 WSL 会话,确保虚拟磁盘没有被占用 wsl --shutdown然后以管理员身份打开 PowerShell,找到你的 vhdx 文件路径(通常在%LOCALAPPDATA%\Packages\...\LocalState\ext4.vhdx),执行压缩:
Optimize-VHD -Path "$env:LOCALAPPDATA\Packages\...\LocalState\ext4.vhdx" -Mode Full如果你的系统没有 Hyper-V 模块,也可以改用 diskpart:
diskpart select vdisk file="C:\Users\MyName\AppData\Local\Packages\...\LocalState\ext4.vhdx" attach vdisk readonly compact vdisk detach vdisk exit压缩完成后,重新打开 WSL,确认里面的文件还在、命令能正常执行。这个操作的本质是把 vhdx 内部已经腾出的空闲空间“归还”给 Windows,让文件体积缩回去。理论上可回收的大小,取决于你在 Linux 里删了多少东西。
4.3 逐项清理的可复现命令
处理完 WSL2 之后,剩下的目录就按部就班来。我建议的顺序是先清 Temp,再清包管理器缓存,因为它们都能自动重建,风险最低。参考命令如下:
# 清空 Temp 临时目录(最好先退出正在运行的程序) Remove-Item "$env:LOCALAPPDATA\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue # 清空 npm 缓存 npm cache clean --force # 清空 pip 缓存(仅当已安装 Python) pip cache purge # 如果使用 pnpm pnpm store prune清完后记得重新统计一次 AppData 的大小,确认释放了多少。当时我从 87.81GB 一路降到了大约 27GB,C盘可用空间从不到 300MB 变成了 61GB 多。看到这个数字,我才真正体会到“不是C盘不够大,而是缓存管不住”这句话的分量。
4.4 清理后必须做的验证步骤
很多教程教完删除命令就结束了,但我必须多说一句:清理完成后至少要正常使用半天再下结论。
我当时的验证清单是:逐个启动常用软件,确认浏览器能正常打开、编辑器配置还在、WSL 里的项目能跑起来、开发依赖能正常安装。没有报错,才算清理成功。别刚删完看C盘变绿就觉得万事大吉,有些软件重建缓存后第一次启动会特别慢,或者某些登录态需要重新验证,这些都要心里有数。
5. 阻止 85GB 再次出现,日常维护该怎么做
5.1 给开发工具的缓存设置上限和迁移路径
这次清理完,我做的第一件事不是放松,而是给那些“缓存大户”上枷锁。缓存不会因为删过一次就自动变乖,它只会以同样的速度再次膨胀。常用的手段有三种:
第一种是给缓存指定非C盘路径。比如 npm 可以把缓存目录迁到 D 盘:
npm config set cache "D:\dev-cache\npm"pip 可以通过设置环境变量改变缓存位置:
# 设置用户环境变量 PIP_CACHE_DIR=D:\dev-cache\pippnpm 则通过配置 store-dir 来实现:
pnpm config set store-dir D:\dev-cache\pnpm第二种是定期清理,比如给自己设一个规则:每月 1 号检查一次 Temp 和各类缓存,超过 5GB 就清一次。不用动脑,靠习惯保证。
第三种是最彻底的,把那些“不可避免会缓存”的目录整体迁到其他盘。这个我会在下面单独说。
5.2 月度磁盘体检清单
我把这次排查的经验整理成了一张简单的体检清单,每个月照着做一次,基本能避免C盘再次悄无声息地爆红:
| 检查项 | 位置 | 达标线 |
|---|---|---|
| 临时文件 | %LOCALAPPDATA%\Temp | 超过 5GB 就清 |
| npm/pnpm/pip 缓存 | %LOCALAPPDATA%\npm-cache等 | 超过 8GB 就清 |
| WSL 虚拟磁盘 | %LOCALAPPDATA%\Packages\...\LocalState | 超过 30GB 就压缩 |
| 浏览器缓存 | 浏览器设置内自带的清理 | 超过 3GB 就清 |
| 更新备份和还原点 | 磁盘清理工具 | 每月看一次即可 |
每次体检不需要像第一次排查那样大动干戈,重点就两个:看趋势,而不是看绝对值。哪个目录比上个月涨了 5GB 以上,就说明它近期有高频写入,要针对性处理。
5.3 AppData 能不能直接整体挪到 D 盘?
我经常看到有人问“能不能把 AppData 整个挪到D盘”。答案是:不要整体挪,但可以有选择地挪。
Windows 和很多软件对路径有硬编码,你把整个 AppData 搬走,可能导致大量软件找不到文件、系统组件失灵。正确做法是只迁移那些“重缓存”目录,然后用目录联接(junction)让原路径仍然指向新位置。
以 npm 缓存为例:
# 1. 把缓存目录从原位置复制到 D 盘 robocopy "%LOCALAPPDATA%\npm-cache" "D:\dev-cache\npm" /E /MOVE # 2. 在原来的位置建立目录联接 mklink /J "%LOCALAPPDATA%\npm-cache" "D:\dev-cache\npm"这样既把空间腾出来给了其他盘,又保留了所有软件按原路径访问的能力。注意事项也很简单:迁移前退出相关软件,迁移后验证软件能正常读写,别在迁移中途断电。
5.4 用 Codex 做持续巡检
经历了这次排查,我意识到 Codex 这类工具还可以更进一步:把月度体检也交给它。你可以让它写一个定期运行的磁盘统计脚本,每次跑完输出一份“占用报告”,按涨跌排名列出最近变化最大的目录。
比如我后面就让 Codex 生成过一个简化的巡检脚本,内容就是统计几个重点目录的大小、对比上次记录、输出差异。这个脚本我每个月手动跑一次,大概十几秒就能看到结果,一旦发现某目录快速增长就能提前处理,而不是等到系统分区彻底变红才动手。
最后再分享一点个人体会
这次排查给我的最大收获不是“删掉了多少GB”,而是建立了一个可复用的判断框架:先搞清楚每个目录是谁创建的、删除后能不能自动重建,再决定动不动手。AppData 里本来就分两种东西——能重建的缓存,和不能重建的配置。用 Codex 来做排查,核心价值就是把“瞎猜”变成“可审计的判断”,让每一步清理都有据可依。
如果你现在也正对着爆红的C盘发愁,别急着装各种清理工具一键狂删。花二十分钟,把一个目录一个目录的大小统计出来,用 AI 助手帮你解释每个目录的用途。你会发现,真正能安全释放的空间往往比想象中大得多,而真正不能动的东西,也比想象中好辨认得多。