1. 先说清楚:WSL2 的数据到底存在 C 盘哪里,为什么会越用越大
用了 WSL2 的人多少都经历过这种场景:明明平时只在里面跑几个命令、装点包,结果某天突然发现自己 C 盘红了,各种磁盘分析工具一扫描,排在最前面的赫然是一个叫 ext4.vhdx 的文件,动辄几十个 GB,而且看起来还在持续增长。我第一次遇到 WSL2 吃满 C 盘是在一个深度学习项目上,当时已经晚了,C 盘只剩不到 3GB,连 Windows 更新都跑不动,只能硬着头皮开始折腾迁移方案。
先说结论:WSL2 的发行版并不是像普通软件那样散装安装在一堆目录里,而是把整个 Linux 文件系统封装进了一个虚拟磁盘文件。这个文件默认放在 C 盘的用户目录下,路径大致是这样的:
code复制C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_xxx\LocalState\ext4.vhdx
如果你同时装了多个发行版,或者 Docker Desktop 使用的 WSL2 后端,那么还会有多个这样的 vhdx 文件。比如 Docker Desktop 在老版本里会额外维护两个发行版:docker-desktop 和 docker-desktop-data,它们的镜像和容器数据也全是 C 盘里的虚拟磁盘文件。
1.1 一个 ext4.vhdx 文件就是整个 Linux 系统盘
理解迁移方案之前,先得把这个 ext4.vhdx 想明白。它本质上就是一个“虚拟硬盘文件”,WSL2 用 Hyper-V 的虚拟化技术,把这一个文件挂载成了 Linux 的根文件系统。你在 WSL2 里做的所有事——apt install 装软件、conda 建环境、拉 Docker 镜像、写代码产生的中间产物——最终都会写入这个文件。
这里有个很反直觉的点:你在这个虚拟磁盘里删文件,磁盘上的剩余空间确实会变大,Windows 桌面上却看不到任何“回收”。因为虚拟磁盘文件属于动态扩展类型,它会随着你写入的数据量不断变大,但删除数据时它只会把块标记为空闲,并不会自动把文件压缩回来。这也是很多人抱怨“WSL2 永远在涨,删了东西也不见减小”的根本原因。
我用最朴素的语言解释一下:这个行为很像你手机上的一个相册备份文件夹,往里面加了 20GB 的照片,它就从 10GB 涨到 30GB,你在里面删掉 15GB 照片,文件夹却往往还是接近 30GB,因为文件系统不会自动整理空间还给存储。WSL2 的虚拟磁盘也一样,必须用专门的命令手动“压缩”体积,这个后面的实操部分会详细说。
1.2 哪些操作最容易让 C 盘“爆炸”
WSL2 的虚拟磁盘占用增长速度,跟你日常做哪些开发工作高度相关。我观察下来,最容易让 C 盘快速爆掉的几类场景是:
- Docker Desktop 的 WSL2 模式:镜像、容器日志、容器内部产生的数据全部分布在 WSL2 的虚拟磁盘里。几个常用镜像加测试环境,轻轻松松吃掉二三十 GB,这是所有场景里最猛的。
- conda / pip / npm 环境:Python 环境本身不大,但依赖包、缓存、
node_modules这些积少成多。一个大型项目的node_modules动辄几个 GB,多开几个项目就是十几个 GB。 - apt 缓存和编译产物:
/var/cache/apt里积压的 deb 包、编译安装时的临时文件、build目录,看起来单个不大,累计起来也是无底洞。 - CUDA 等开发工具链:装 CUDA Toolkit、cuDNN、TensorRT 这类组件,单件就是几个 GB 起步。在 WSL2 里跑深度学习或者做 AI 推理测试的人,虚拟磁盘膨胀速度非常夸张。
我自己当时的情况是,Ubuntu 发行版本身系统文件不到 6GB,但加上 conda 环境和几个模型权重文件,整体到迁移前已经占用 80 多 GB。说句实在话,WSL2 不是装完就完事的玩具,它是实打实的完整 Linux 系统,C 盘本身就是系统盘,Windows 更新、页面文件、休眠文件都要地方,两者叠加,空间告急只是时间问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前的准备:备份、空间确认与迁移方案选型
很多人一听到迁移,第一反应是直接去安装目录里把那个 vhdx 文件复制到 D 盘,再改个注册表或者路径。这思路听着简单,实际操作起来很容易踩坑,所以我强烈建议别急着动手,先花十分钟把准备工作做完。
2.1 先摸清家底:查看发行版列表、版本和占用
第一步,打开 PowerShell(我用的是 Windows 11,Windows 10 也是一样的操作),执行:
powershell复制wsl -l -v
这个命令会列出所有已安装的 WSL 发行版以及它们当前的状态和 WSL 版本。比如我的机器当时显示:
code复制 NAME STATE VERSION
* Ubuntu Running 2
docker-desktop Stopped 2
docker-desktop-data Stopped 2
看到这个列表后,你心里要有个数:需要迁移的不是“WSL2”这一个笼统的对象,而是每一个具体发行版。如果你只是因为日常开发用 Ubuntu,那只要迁 Ubuntu 就行;如果你还跑着 Docker Desktop,那 docker-desktop-data 里装的才是 Docker 镜像大头,不迁它等于白迁。
第二步,看看这些虚拟磁盘实际占了多大。在资源管理器的地址栏输入 %LOCALAPPDATA%\Packages,然后找到对应的发行版文件夹,进入 LocalState 目录,查看 ext4.vhdx 的属性。这里看到的文件大小就是虚拟磁盘文件的真实占用。
第三步,确认一下默认发行版是谁,也就是 wsl -l -v 列表里带 * 的那个。迁移后默认发行版的设置可能会丢,得记下来,后面恢复。
2.2 备份与空间规划:别等硬盘满了才后悔
准备工作里最重要的一件事永远是备份。WSL2 的迁移操作本身不复杂,但中间涉及注销发行版,一旦操作失误,系统里的所有配置、数据、代码就全没了。
备份方式很简单,就是一条导出命令,把整个发行版导出成一个 tar 文件。不要把备份文件放在 C 盘,尤其是你现在 C 盘都快满了的情况下。我当时是在 D 盘建了一个 D:\wslbackup 目录,专门用来放导出文件。
这里有个空间规划问题容易被忽视:导出的 tar 文件大小通常小于 vhdx 的实际占用,但也不小。我那个 80GB 的发行版,导出的 tar 文件大约 42GB。如果你 D 盘只剩 40GB 空闲,那这个操作就行不通。执行导出前,建议先清理一下 WSL 里的垃圾:删掉不用的 conda 环境、清空 apt 缓存、把 Docker 里不用的镜像 prune 掉,然后再导出,既减小备份体积,也减小后面迁移的耗时。
2.3 方案对比:export/import 和直接挪 vhdx
网上关于 WSL2 迁移的方法五花八门,归纳起来本质上是两条路线:
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
wsl --export + wsl --import |
把发行版整体导出为 tar,再导入到新路径 | 官方支持、操作直观、不容易出幺蛾子 | 导入后默认用户会变成 root,需要额外修复 | 第一次迁移、重要数据多、追求稳妥 |
| 直接移动 vhdx + 创建目录联接 | 把整个发行版文件夹剪切到 D 盘,在原位置用 mklink /J 建一个目录联接 |
不改变发行版内部任何东西,用户、软件配置全保留 | 对文件操作要求高,路径稍有疏忽就找不到发行版 | 数据已经在上一种方案迁移过了、想换位置的二次迁移 |
如果让我给个选择建议,第一次迁移、手里数据重要的用户,无脑选 export/import。它不是最快的方法,但每一步都能看得见结果,出问题也能从 tar 文件恢复。直接移动 vhdx 文件的方案,适合对文件系统原理比较熟的玩家,而且需要保证原文件夹和目标文件夹在同一个分区操作时不会出现文件占用问题,否则很容易中途失败。
3. 核心实操:export + import 迁移 WSL2 到 D 盘
准备工作做完,下面就是正式迁移。整个过程我拆成三个大步:导出、注销并导入、恢复配置。以下命令我都用管理员身份的 PowerShell 执行,建议你也这么做,很多权限问题可以提前规避。
3.1 第一步:干净地关停 WSL,导出发行版镜像
迁移前一定要确保目标发行版处于停止状态。你可以在终端里先执行:
powershell复制wsl --shutdown
这条命令会停止所有 WSL2 发行版并释放虚拟化资源。不加这一步直接导出,尤其当发行版还在运行时,虽然通常也能导出成功,但文件系统状态可能不是最干净的,恢复后出现偶发文件问题很烦。
然后执行导出。以我迁移 Ubuntu 为例:
powershell复制wsl --export Ubuntu D:\wslbackup\ubuntu_backup.tar
参数说明:第一个参数是发行版名称,必须和 wsl -l -v 里显示的完全一致;第二个参数是导出的 tar 文件路径,建议直接放到 D 盘。新版 WSL 还支持 wsl --export 带 --vhd 参数导出成 VHD 虚拟磁盘文件,但我个人觉得 tar 格式更通用,恢复时兼容性也更好,所以这里不做展开。
导出过程没有进度条,屏幕上就一个光标在闪。我当时以为卡住了,差点按 Ctrl+C,实际它只是闷头干活。几十 GB 的发行版导出,少则十分钟,多则半小时,这段时间你该干嘛干嘛,但别打开 WSL 里的任何程序,也别在同一终端里跑其他 wsl 命令,否则可能触发导入导出文件锁冲突。
提示:导出完成后,如果你 C 盘空间严重不足,可以先验证一下 tar 文件能正常打开,再把 C 盘里原来的发行版目录留着。安全第一,宁可多占点空间,也别过早动手删原文件。
3.2 第二步:注销旧发行版,把镜像导入 D 盘
确认 tar 文件已生成且大小正常后,执行注销命令:
powershell复制wsl --unregister Ubuntu
这里要特别强调:unregister 会把该发行版从 WSL 的注册表中移除,并删除它所有的数据文件,包括它在 C 盘里的整个文件夹。这一步是不可逆的,只要执行了,C 盘那个几十 GB 的 ext4.vhdx 就会被直接删掉。所以再次确认你已经成功导出了 tar 文件,且那个 tar 文件不是个空壳。
注销完成后,在 D 盘创建要放置新发行版数据的目录,然后导入:
powershell复制mkdir D:\WSL\Ubuntu
wsl --import Ubuntu D:\WSL\Ubuntu D:\wslbackup\ubuntu_backup.tar --version 2
这里三个关键参数逐一说明:第一个 Ubuntu 是导入后的发行版名称,你可以改成任何名字,比如 Ubuntu-D,但要和原来的应用配置、Windows Terminal 配置对得上,后续命令里的名称也得跟着变,所以我建议保持原名;第二个 D:\WSL\Ubuntu 是新的数据目录,导入后该目录下会自动出现 ext4.vhdx 文件;第三个是刚才导出的备份文件路径。--version 2 的意思很明确:确保按 WSL2 格式导入。如果你的机器上还同时留着 WSL1 的发行版,这一步尤其重要。
导入执行完,马上验证一下:
powershell复制wsl -l -v
此时你应该能看到刚刚导入的发行版,但状态可能是 Stopped,名称后面还有 VERSION 为 2 的标志。再试试启动它:
powershell复制wsl -d Ubuntu
不出意外你会直接进到 root 身份——原因后面会说。到这里,数据已经从 C 盘落到了 D 盘,核心迁移动作已经完成,剩下的都是修复和验证工作。
3.3 第三步:恢复默认用户、网络和桌面集成
导出的 tar 里不会包含“当前默认用户是谁”这个 WSL 元信息,所以 import 之后默认用户被重置成了 root。这不是数据丢失,只是配置问题,修一下就行。
最省事的办法是在 PowerShell 里直接调用发行版的配置工具。以 Ubuntu 为例,执行:
powershell复制ubuntu config --default-user 你的用户名
如果你安装的是 Ubuntu 24.04,这个命令一般直接可用;如果是老版本,可能是 ubuntu.exe config --default-user。还有一种更通用的做法:进入 WSL,以 root 身份编辑 /etc/wsl.conf:
bash复制sudo sh -c 'echo -e "[user]\ndefault=你的用户名" > /etc/wsl.conf'
然后 wsl --shutdown 再重新进入,执行 whoami 确认用户已经恢复正常。两条路都能走,我个人遇到 ubuntu config 在自定义发行版名称时偶尔失效,所以更推荐写 wsl.conf,对任何发行版都管用。
接下来检查网络。WSL2 默认走 NAT 模式,一般不用动。但如果你之前为了项目需要配置过端口转发规则,或者改过 WSL 内部的自定义网络配置,迁移后这些规则可能会失效,需要重新核对。开发用的项目端口、数据库端口这些,多留意一下能不能从 Windows 侧正常访问到 WSL 内部的服务。
桌面集成方面,如果你用的是 WSLg(Windows 11 默认)或者自己装了 X Server 做图形界面转发,迁移后一般不受影响,因为它们依赖的是 WSL 里的 Linux 程序和 Windows 侧的显示服务。但如果你给 WSL 配置过 DISPLAY 环境变量,导入后可能要顺手确认一遍。
4. 迁移之后的重头戏:磁盘回收与空间管理
迁移完成不是终点,反而是管理 WSL2 空间的新起点。很多人迁到 D 盘后就直接不管了,结果半年之后告诉你 D 盘也满了——这不是 WSL2 的问题,是磁盘瘦身这事压根没做。我在这节把磁盘体积控制和 Docker Desktop 的迁移一起讲了。
4.1 释放虚拟磁盘空间:vhd 压缩的两种办法
前面说了,WSL2 的虚拟磁盘只会膨胀不会自动缩小。哪怕你在系统里删了几十 GB 文件,D 盘上的 ext4.vhdx 也不会自己变小。想要真正回收空间,必须手动 compact 一次。
先进入 WSL,执行一次文件系统回收,把文件系统里标记为空闲的块清理一下,这一步能显著提升压缩效果:
bash复制sudo fstrim / && sudo fstrim /
我常看到有人只跑 fstrim / 一遍,但实际在部分 WSL2 内核上,跑两遍效果更稳定,这算个小经验。然后关掉 WSL:
powershell复制wsl --shutdown
再打开 diskpart。diskpart 是 Windows 自带的磁盘工具,在 PowerShell 里启动后依次执行以下命令:
text复制select vdisk file="D:\WSL\Ubuntu\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
第一行 select vdisk 指定要处理的虚拟磁盘文件;第二行以只读方式挂载它;第三行执行压缩;第四行卸载。整个过程看起来没什么输出,但跑完后你会看到文件大小明显减小。我压缩过一次,一个 60GB 的虚拟磁盘最终降到了 20GB 左右,效果非常明显。
另一种方法是用 Hyper-V 的 PowerShell 模块:Optimize-VHD -Path "D:\WSL\Ubuntu\ext4.vhdx" -Mode Full。这个方法一样有效,但要求你的 Windows 版本带有 Hyper-V 管理工具,家庭版没有这个功能,所以我更推荐 diskpart,因为它全系 Windows 都能用。
注意:无论是 diskpart 还是 Optimize-VHD,执行前必须确认 WSL 已经完全关闭,否则虚拟磁盘文件被占用,命令会报错。
4.2 给 WSL2 做资源约束,顺便把 swap 也挪走
很多人不知道,WSL2 的 swap 文件默认也是放在 C 盘的,具体路径在用户目录下面的 AppData\Local\Temp\swap.vhdx。如果你平时在 WSL 里跑编译或者模型推理,内存吃紧时这个 swap 文件也会悄悄增长。
在 C:\Users\你的用户名\.wslconfig 文件里,可以统一管理 WSL2 的资源分配。比如:
ini复制[wsl2]
memory=8GB
processors=4
swap=2GB
swapFile=D:\\WSL\\swap.vhdx
前两行限制 WSL2 使用的内存和 CPU 核心数,避免它拖动整个系统的性能;第三行和第四行则把 swap 文件直接放到 D 盘,并且固定大小为 2GB。改完保存,执行 wsl --shutdown 再重新启动,配置就会生效。
这套做法对 C 盘瘦身的意义在于:除了 ext4.vhdx,WSL2 在系统盘上的其他附属文件也一起转移出去了。迁移前记住这个思路,很多用户只盯着发行版的 vhdx,却漏掉了 swap,最后 C 盘清出来的空间打完折扣。
4.3 Docker Desktop 的 WSL2 后端怎么挪到 D 盘
本地开发几乎绕不开 Docker Desktop。如果你已经启用 WSL2 后端,Docker 的镜像、容器数据默认存进 WSL 发行版 docker-desktop-data 的虚拟磁盘里,它的位置同样在 C 盘用户目录。所以迁移 WSL2 发行版的时候,顺手把 Docker 的数据也迁走,才算真正根治 C 盘空间问题。
先检查一下 Docker Desktop 的设置。较新的版本里,在 Docker Desktop 的 Settings -> Resources -> Advanced 下有一个 Disk image location 选项,直接指向一个目录,点 Apply & Restart 后 Docker 会自动重建数据目录。如果用的是这个界面设置,其实根本不需要碰命令行;但老版本或者设置界面路径不明确时,就得手动迁移。
手动迁移的思路跟 WSL2 发行版类似:
powershell复制wsl --shutdown
wsl --export docker-desktop-data D:\wslbackup\docker-desktop-data.tar
wsl --unregister docker-desktop-data
mkdir D:\WSL\docker-desktop-data
wsl --import docker-desktop-data D:\WSL\docker-desktop-data D:\wslbackup\docker-desktop-data.tar --version 2
迁移完成后,重新启动 Docker Desktop,让它以 WSL2 模式重新连接这些数据。第一次启动可能需要多等一会儿,因为 Docker 引擎要重新识别新的磁盘路径。这里有个细节:如果你还保留了 docker-desktop 发行版,只需要迁移 docker-desktop-data 就行,docker-desktop 本身体积很小,不过它是 Docker 的辅助发行版,通常不用管,迁它的意义不大。
5. 迁移过程中的常见报错与避坑实录
任何技术操作都不可能一帆风顺,我把自己和周围朋友踩过的坑整理成速查表。这些报错很多不是迁移本身的问题,而是操作习惯和环境导致,遇到时可以对照排查。
5.1 高频报错速查表
我先列一个排查表格,方便你保存参考:
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
There is no distribution with the provided name |
发行版名称写错了 | 用 wsl -l -v 查看准确的名称再执行 |
The system cannot find the file specified |
tar 路径不对,或者路径里有空格没加引号 | 给路径加英文双引号,确认文件真实存在 |
Import in progress |
导入未完成就执行了其他 wsl 命令 | 等导入彻底结束,或重启终端再操作 |
The process cannot access the file because it is being used by another process |
ext4.vhdx 被 WSL 进程占用 |
先 wsl --shutdown,必要时管理员模式重开终端 |
0x80370102 |
虚拟化相关服务未启动 | 检查 Windows 功能里的“虚拟机平台”,开启后重启 |
0x80070005 |
权限不足 | 用管理员身份运行 PowerShell |
Error code: Wsl/0x8004036d |
WSL 服务状态异常 | 执行 wsl --shutdown 后重启电脑,再试一次 |
我见过最多的失败案例发生在“导入过程中打开另一个 WSL 窗口”这种操作上。WSL 对发行版数据的锁管理不算强,但你同时跑两个操作,很容易撞锁。所以我的建议是:从 wsl --shutdown 到导入完成,中间这一个过程,不要打开任何 WSL 相关窗口。
5.2 迁移后默认用户变 root 的修复
导入后你会发现每次进入 WSL 都是 root,这是正常的,因为 wsl --import 生成的发行版不会自动带默认用户信息。千万不要以为自己系统坏了。
修复方法在上面 3.3 节已经写过,这里再补充一点:如果你导入时把发行版名称改了,比如叫 Ubuntu-D,那用 ubuntu config --default-user 这类命令时,它可能找不到匹配的配置文件。这时直接进入 WSL、编辑 /etc/wsl.conf 是最保险的。写完 wsl.conf 后一定要 wsl --shutdown 再进,因为 WSL 只在发行版启动时读取配置,不会热更新。
还有个细节:如果你之前在 WSL 里配过 SSH 密钥、git 配置,这些都在文件里,不受迁移影响;但如果你在 /etc/profile.d/ 或者 .bashrc 里写了依赖绝对路径的脚本,迁移后路径如果变了也要顺手改。
5.3 C 盘其他大头:conda、缓存目录的顺手迁移
迁完 WSL2,C 盘一般能腾出不少空间。但如果你平时还重度使用 conda、npm 这类工具,它们的缓存同样占着 C 盘用户目录。这里给几个顺手就能做的处理:
- conda 虚拟环境迁移:修改
~/.condarc里的envs_dirs和pkgs_dirs,指向 D 盘的目录,然后把旧的envs文件夹用mklink /J链接到新位置,这样不破坏已有环境的绝对路径。 - npm / pip 缓存:npm 的缓存目录可以用
npm config set cache D:\npm-cache改到 D 盘;pip 可以通过环境变量PIP_CACHE_DIR重定向。 - C 盘清理命令:常用的
cleanmgr可以清理系统临时文件和更新缓存,dir /s可以快速找出大文件,但这些放在 C 盘本身已经很满的时候效果有限,更根本的办法是把能挪的目录都挪去其他分区。
我并不是让你把所有东西都塞到 D 盘,而是建议建立“系统盘只留系统”的习惯。C 盘是固态硬盘上系统稳定性最关键的分区,空间紧张不但影响日常操作,还会直接影响休眠文件和系统更新的可用性。
6. 几次迁移下来,我的几点体会
前后给三台电脑做过 WSL2 迁移,自己也重装过无数次,最后说点实在体会。第一次迁移时我犯了个典型错误:没有先备份就试着直接复制 ext4.vhdx,结果由于文件被 WSL 占用,复制完的磁盘死活挂载不上。后来老老实实走 export/import 方案,一步到位,再也没有翻过车。所以说,官方提供的导入导出命令虽然慢,但稳定就是它最大的优势。
第二个体会是,迁移这件事最好在装完 WSL2 之后趁早做。很多人刚开始用 WSL2 时觉得数据量小,无所谓,等到 D 盘项目堆起来、模型权重好几百 GB 的时候再迁,导出文件动辄上百 GB,费时费力。装好系统那天就把发行版迁到 D 盘,后面完全不用再纠结。
最后分享一个小技巧:迁移完成后,如果你还有别的发行版要处理,或者想把整个流程固定下来,可以把 wsl --shutdown、wsl --export、wsl --import 这几条命令串成一个 bat 脚本,放在 D 盘,以后换机或者重装系统时直接执行一遍。我自己就是这么干的,每次换电脑,半小时搞定 WSL 环境,比重新装各种依赖省太多时间。WSL2 的数据本来就是一堆文件加一份配置,理清了这个思路,它就不再是 C 盘的心头大患了。
