快速修复
# 一键:确认 vhdx 位置 + 宿主盘剩余空间(PowerShell)
Get-ChildItem "$env:LOCALAPPDATA\Packages\*\LocalState\ext4.vhdx" | Select FullName, @{n='GB';e={[math]::Round($_.Length/1GB,1)}}
Get-PSDrive C | Select Used, Free
宿主盘清出空间后 WSL 立即恢复写入。
你会遇到什么
WSL 里解压/编译/写入大文件时报 No space left on device,但 df -h / 明明显示还有几百 G 可用(/dev/sdd 1007G 190G 766G 20% /)。你第一反应是"我明明有空间"——这是 WSL2 最经典的悖论:df 显示的是虚拟容量,不是宿主盘上 vhdx 文件的真实大小。
本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。
为什么会这样
WSL2 的 ext4 文件系统建在动态扩张的 vhdx 虚拟磁盘上:
df显示虚拟容量(默认最大 1TB 级);- 写入需要 vhdx 物理扩张时,要求宿主盘(默认 C 盘)有剩余空间;
- 宿主盘满了 → 扩张失败 → 内核返回 ENOSPC(No space left on device)。
于是出现「df 显示有空间、实际写不进去」的悖论。经典 issue:microsoft/WSL#1665(随机 ENOSPC)、#4699(372 comments:删了文件 vhdx 也不还给宿主)。
实测环境:WSL Ubuntu,vhdx 在 D:\WSL\Ubuntu,宿主 D 盘仅剩 9GB,2026-08-29。
WSL2 的 ext4 文件系统住在一个 vhdx 虚拟磁盘里:df 显示的是虚拟磁盘的容量上限(默认 1TB 级),而真实占用来自 vhdx 文件的物理扩张。写文件需要扩张时,内核向宿主盘(默认 C 盘)申请空间——宿主盘满了,扩张失败,内核就把这次写入判为 ENOSPC。于是出现「虚拟容量显示有空间、物理宿主没空间」的双层账本悖论。
确定性推论:df -h / 有空间但写不进 = 查宿主盘(df -h /mnt/c)和 vhdx 实际大小(ls -lh *.vhdx);删了文件 vhdx 也不缩小是正常行为(稀疏文件只缩不自动回收),需要 wsl --shutdown 后 Optimize-VHD/diskpart compact 手动压缩;
长期解法是把发行版迁到空间大的盘(wsl --export/--import)而不是在快满的盘上硬撑。
一步步来
1. 定位 vhdx 在哪个盘 — 排查
PowerShell:
Get-ChildItem "$env:LOCALAPPDATA\Packages\*\LocalState\ext4.vhdx" | Select FullName
或注册表 HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\{GUID} 的 BasePath。
2. 看宿主盘剩余 — 必做
Get-PSDrive D
宿主盘 Free 很小(本机实测 D 盘剩 9GB 时 WSL 内写 2.7G 就 ENOSPC)→ 清宿主盘空间(回收站/大文件/其他发行版 vhdx)即可立即恢复。
3. 让 vhdx 归还空间(治本,删了文件不缩盘) — 必做
- 新 WSL(2.4.4+):
wsl --shutdown后wsl --manage <发行版> --set-sparse true,删除文件自动还空间; - 老版本:
wsl --shutdown+ 管理员 diskpartcompact vdisk(或 Hyper-VOptimize-VHD)。
4. 换大盘 — 必做
wsl --export <发行版> <文件.tar>
新位置 wsl --import <发行版> <目录> <文件.tar>(import 后默认 root/默认发行版要重设,wsl --set-default)。
5. 防患 — 必做
docker-desktop 等发行版也各自占 vhdx;大文件放 /mnt/c(直通宿主盘,不占 vhdx)。
怎么确认修好了
dd if=/dev/zero of=/tmp/x.bin bs=1M count=5120 conv=fsync && rm /tmp/x.bin
不再报 No space left on device 即成功。实测:宿主盘清理前写 5GB 在 ~2.7GB 处报错、df 仍显示 766G 可用;清理后恢复。
其它环境的表现
| 环境 | 说明 |
|---|---|
| 默认安装(C 盘) | vhdx 在 %LOCALAPPDATA%\Packages\*\LocalState\,清 C 盘 |
| 迁移到 D 盘 | 清 D 盘;本机实测 D 盘剩 9GB 即触发 |
| 删了文件空间没回来 | vhdx 不自动缩,用 --set-sparse / diskpart compact |
| docker-desktop | 其 vhdx 单独占空间,同样处理 |
症状
WSL 里解压/编译/写入大文件时报 No space left on device,但:
$ df -h /
/dev/sdd 1007G 190G 766G 20% / # 明明还有 766G 可用
$ dd if=/dev/zero of=/tmp/x.bin bs=1M count=5120 conv=fsync
dd: IO error: No space left on device # 写 ~2.7G 就失败
特征:df 显示可用空间充足(甚至 80% 空闲);失败点随机(解压到不同文件); 用户第一反应是"我明明有空间"(microsoft/WSL#1665 原话 I do have enough space on my device)。
原因
WSL2 的 ext4 文件系统建在动态扩张的 vhdx 虚拟磁盘上:df 显示的是虚拟容量(默认最大 1TB 级), 不是宿主盘上 vhdx 文件的实际大小。当 WSL 内写入需要 vhdx 物理扩张,而 vhdx 所在的宿主盘 (默认 C 盘,或迁移后的盘)剩余空间不足时,扩张失败 → 内核返回 ENOSPC。 于是出现「df 显示有空间、实际写不进去」的悖论。相关经典 issue: microsoft/WSL#1665(随机 ENOSPC)、#4699(372 comments:删了文件 vhdx 也不还给宿主)。
解法
- 先定位 vhdx 在哪个盘:注册表
HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\{GUID}的 BasePath,
或 PowerShell Get-ChildItem "$env:LOCALAPPDATA\Packages\*\LocalState\ext4.vhdx";
- 看宿主盘剩余:
Get-PSDrive检查 vhdx 所在盘 Free——本机实测 D 盘只剩 9GB 时 WSL 内写 2.7G 就 ENOSPC。
清宿主盘空间(回收站/大文件/其他发行版 vhdx)即可立即恢复;
- 让 vhdx 归还空间(治本,删了文件不缩盘):
- 新 WSL(2.4.4+):
wsl --shutdown后wsl --manage <发行版> --set-sparse true,vhdx 稀疏化,删除文件自动还空间; - 老版本:
wsl --shutdown+ 管理员 diskpartcompact vdisk(或 Hyper-VOptimize-VHD);
- 换大盘:
wsl --export <发行版> <文件.tar>→ 新位置wsl --import <发行版> <目录> <文件.tar>(注意 import 后默认 root 用户/默认发行版要重设,可wsl --set-default); - 防患:docker-desktop 等发行版也各自占 vhdx;大文件放 /mnt/c(直通宿主盘,不占 vhdx),
或把 vhdx 容量上限调小(wsl --resize 部分版本支持)。
验证证据
- 本地实测(2026-08-29,WSL Ubuntu,vhdx 在 D:\WSL\Ubuntu,宿主 D 盘仅剩 9GB):
- 基线:df 显示 766G 可用 / vhdx 文件 194.90GB / D 盘 Free 9.0GB;
- 复现:dd 写 5GB 在 ~2.7GB 处报
IO error: No space left on device,随后df -h /仍显示 766G 可用; - 机制核对:D 盘 Free 9GB(vhdx 无物理空间可扩),df 是虚拟容量——与 #1665 症状同款;
- 清理:删除部分文件后 df 恢复,D 盘 Free 不变、vhdx 大小不变(删除不还空间,即 #4699 诉求点);
- 未实测(需管理员/重启,如实标注):diskpart compact、--set-sparse、--export/--import 迁移。
- 实测复现日志(2026-08-29)
相关 canonical
按「前置 → 同根 / 同域 / 相关」读:
- 同根(同一根因):
- docker pull 失败/镜像加速(同根:pull 拉取/解压阶段报
no space left on device,真相常是 WSL 宿主盘满——先查 vhdx 所在盘剩余空间) - Docker daemon 连不上(同根:Docker 侧连接/环境类,先排除 daemon 状态再查磁盘)
- ollama pull 卡住/超时(同根:模型下载/导入阶段 ENOSPC,模型 4~70GB 先查盘)
- pip 安装超时/慢(同根:下载/安装阶段 ENOSPC)
- npm install 慢/挂起(同根:缓存写入阶段 ENOSPC)
- Go 模块拉取慢/超时(同根:下载/构建阶段 ENOSPC)
适用工具 (1)
本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。
wsl · 外部工具成套方案 (组合包)
这个问题包含在下列成套安装方案中。
- 容器与 WSL 环境成套配置与排查 partial
来源与证据
← 编码代理与终端 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡