如果你跟我一样,日常开发环境就是 Windows 上加一套 WSL 的 Ubuntu,那你迟早会撞上同一个问题:C 盘又快满了。WSL 默认会把整个发行版塞进系统盘,一个 ext4.vhdx 文件随随便便几十个 G。平时装个 CUDA、跑两个 Docker 容器、再编译几轮 Node 或者 Rust 项目,磁盘占用就像滚雪球。把 WSL 从 C 盘搬到其他磁盘,不是可做可不做的优化,而是很多人的刚需。
这篇文章我会把 WSL 的存储机制、迁移方案的取舍、完整操作步骤、迁移后的优化和踩坑记录全部分享出来。整理的工具和命令都是我在实际环境中验证过的,照着做基本不会翻车。适合被 C 盘空间折腾到头大的 WSL 用户,也适合刚装完系统想从一开始就规划好磁盘布局的新手。
1. 先搞明白:WSL 为什么占 C 盘,迁移前要准备什么
1.1 WSL1 与 WSL2 的存储差异
先说一个很多人混淆的概念:WSL 1 和 WSL 2 在存储上完全是两套逻辑。
WSL 1 是类似 API 映射的兼容层,Linux 的文件系统直接落在 Windows 目录里,你看到的那个发行版文件夹就是一个真实的目录树。WSL 2 则完全不同,它跑在一个轻量级虚拟机上,整个 Ubuntu 的文件系统被封装进一个虚拟磁盘文件里,这个文件就是常说的 ext4.vhdx。你在 Ubuntu 里执行 ls -l 看到的所有文件、安装的每个包、跑过的每个容器数据,全都在这个 vhdx 内部。
这个虚拟磁盘默认放在当前用户的 LocalAppData 目录下,具体路径类似:
code复制C:\Users\<你的用户名>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu...\LocalState\ext4.vhdx
不同渠道安装的 Ubuntu 前缀会有差异,但位置都在 Packages 目录里。我见过不少人以为 WSL 就是个普通的 Linux 工具,卸载掉数据就没了。实际上 WSL 的发行版数据独立性很强,卸载 App 不等于删除虚拟磁盘。这既是好事(数据不容易误删),也是麻烦(空间不知不觉被吃光)。
1.2 为什么 vhdx 会越用越大,删除文件却不缩小
WSL 2 的虚拟磁盘默认是动态扩展的。什么意思?它一开始创建的物理文件很小,比如 2 个 G,随着你在里面写数据,文件会逐渐变大,但一旦你删除了里面的文件,这个 vhdx 物理文件却不会自动缩小回来。
我举个实际场景:你在 Ubuntu 里下载了一个 10 GB 的数据集跑算法,用完以后 rm -rf 删掉了。你以为磁盘空间回来了,看看 C 盘你会发现还是少了 10 个 G。原因就是 vhdx 文件已经在物理上扩展到了对应大小,虚拟磁盘不会因为文件系统内的删除操作自动收缩。
这一点直接决定了迁移的时候不能简单粗暴地复制 vhdx 了事。如果你把已经膨胀到 30 GB 的 vhdx 直接搬去 D 盘,那这 30 GB 依然被占用着。正确做法是先把虚拟磁盘压缩到合理大小再迁移,或者迁移后做一次压缩。后面的实操部分我会讲这一步怎么处理。
1.3 迁移前检查清单
动手之前,先花五分钟确认几件事,能避免后面很多麻烦。
第一,确认你的 WSL 版本和发行版名称。
code复制wsl -l -v
这个命令会列出所有已安装的发行版和版本号,比如 Ubuntu、Ubuntu-22.04、Debian 等。不同机器上发行版名称可能不一样,后续所有命令里的名字都必须和这里显示的一致,粘贴复制的时候千万别改。
第二,确认 WSL 本身的版本。
code复制wsl --version
新版 WSL 会有独立的版本号,支持 --vhd 参数和 wsl --manage 指令。老版本先执行 wsl --update 升级。
第三,确认目标磁盘的文件系统和剩余空间。
WSL 的磁盘文件也遵守 Windows 的基本规则,NTFS 格式下没有任何问题,FAT32 不推荐,因为单文件大小限制会导致迁移失败。建议目标盘至少留出和当前 WSL 占用同等大小的空间,最好再富余 20% 左右。导出时还会生成一个临时备份文件,这个文件也需要空间,记得把这块也计算进去。
第四,重要数据先备份。
虽然迁移过程本身不会丢数据,但是任何磁盘操作都有风险。特别重要的项目、数据库数据、配置文件,建议先在 Ubuntu 里打包一份放到 Windows 目录下,或者推送到远端仓库。这一步花不了几分钟,但能救你一次。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三种搬家方案,为什么我推荐 export/import
2.1 方案一:wsl --manage --move,最快但有前提
新版 WSL(0.67.0 以上)提供了一个看起来最直接的命令:
code复制wsl --manage Ubuntu --move D:\WSL\Ubuntu
这一条命令就能把发行版移动到新路径,速度很快,因为它就是简单地搬运 vhdx 文件并更新注册信息。听起来完美对吧?但有两个问题:
一是兼容性。这个命令要求你的 WSL 版本足够新,Windows 10 的老版本不一定能用。二是一个隐患:它是直接搬运物理文件,不会对虚拟磁盘做任何优化。如果原来的 vhdx 已经膨胀到 40 GB,搬完还是 40 GB。而且移动过程中一旦中断,两边都可能留下不完整的文件。
我的建议是:如果你只是需要一个简单的迁移,且确认 WSL 版本很新,这个方案可以用。如果你对磁盘占用已经很在意,想顺便给 vhdx 减重,或者你的版本比较旧,那就看下面的方案二。
2.2 方案二:wsl --export / wsl --import,最稳妥的通用路线
这是跨发行版、跨机器、跨版本的通用方案,也是 WSL 官方文档推荐的迁移方式。核心思路很简单:把整个发行版导出成一个备份文件,再把备份文件导入到新位置。
code复制wsl --export Ubuntu D:\wsl-backup\Ubuntu-backup.tar
wsl --import Ubuntu D:\WSL\Ubuntu D:\wsl-backup\Ubuntu-backup.tar --version 2
导出会老老实实地走一遍文件系统,把 Ubuntu 里的所有文件和权限重新组织一遍,导入时再在新位置重建虚拟磁盘。这相当于给系统做了一次完整的“序列化”,兼容性最好。同时,因为导出的是文件流而不是原始的 vhdx 块,最终导入生成的 vhdx 是全新的,原有磁盘碎片和空洞都会消失,文件可能比原来还小一些。
WSL 的新版本还支持 --vhd 参数,可以直接导出成 vhdx 文件。这种方式更适合在 Windows 上对虚拟磁盘做精细操作,导入效率也比 tar 格式高。缺点是只能在 WSL 2 之间使用,如果目标环境是 WSL 1 就不适用。
2.3 方案三:直接复制 vhdx + 改注册表,不推荐
网上能搜到一些教程,让你把 ext4.vhdx 复制到 D 盘,然后去注册表里改 BasePath。这个方案听起来省事,实际上有明确的坑:WSL 注册表里的参数不只路径一项,还涉及版本、状态、权限等信息,手动改动很容易造成发行版无法启动。就算改对了,虚拟磁盘还是原来那个,没有瘦身效果,碎片问题也带过去了。
除非你非常熟悉注册表结构和 WSL 的工作机制,否则没必要冒这个险。有现成的官方命令不用,非要去手改注册表,属于给自己找事。
2.4 方案对比小结
| 方案 | 操作难度 | 风险 | 是否优化磁盘 | 适用场景 |
|---|---|---|---|---|
| wsl --manage --move | 极低 | 中 | 否 | WSL 版本较新,只想快速搬家 |
| export / import | 中 | 低 | 是 | 通用性强,跨机器/跨版本迁移 |
| 复制 vhdx + 改注册表 | 高 | 高 | 否 | 不推荐 |
最终我建议绝大多数人采用方案二。操作多几步,但每一步都可以验证,出了问题容易回滚,心理也有底。
3. 完整实操:把 Ubuntu 从 C 盘迁到 D 盘
下面进入正题。我以最常见的 Ubuntu 发行版为例,目标盘选择 D 盘。整个流程分为四步:关停系统、导出备份、导入新位置、验证并清理。
3.1 第一步:关闭 WSL 并导出发行版
迁移前首先要确保 WSL 处于完全停止状态,因为导出操作要求发行版没有被占用,否则文件可能不一致。
code复制wsl --shutdown
这条命令会关闭所有发行版。如果你之前在 Ubuntu 里开了会话,建议先在 Ubuntu 内保存好工作,再在 Windows 终端执行这条命令。
接下来确认发行版名称:
code复制wsl -l -v
假设输出里有 Ubuntu 这一行,就继续导:
code复制wsl --export Ubuntu D:\wsl-backup\Ubuntu-backup.tar
导出过程根据数据量大小不同,快则两三分钟,慢则可能十几分钟。如果你在 Ubuntu 里装了很多东西,文件特别多,耐心等。导出期间 Windows 终端会出现一个进度条,但不会显示百分比,只有转圈。
如果你用的是比较新的 WSL,并且确认目标发行版是 WSL 2,也可以导出为 vhdx 格式:
code复制wsl --export Ubuntu D:\wsl-backup\Ubuntu-backup.vhdx --vhd
两种格式我后面会对比说明怎么选。对于第一次操作的用户,tar 格式最稳妥,所有环境通用。
注意:导出文件所在的分区最好和目标安装位置不是同一个。如果 D 盘空间紧张,可以先导出到 C 盘临时目录,导入完成后再删。
3.2 第二步:导入到 D 盘新位置
先在 D 盘规划一个清晰的目录结构,我习惯这样:
code复制D:\WSL\Ubuntu
以后所有发行版都放在 D:\WSL 下,每个发行版一个子目录,移动和查找都方便。然后在 Windows 终端执行:
code复制wsl --import Ubuntu D:\WSL\Ubuntu D:\wsl-backup\Ubuntu-backup.tar --version 2
这条命令的参数拆开来看:
Ubuntu:发行版名称,导入后会以这个名字注册。D:\WSL\Ubuntu:新的安装目录,vhdx 文件会生成在这里。Ubuntu-backup.tar:第一步生成的备份文件。--version 2:明确指定导入为 WSL 2。
如果你导出时用的是 --vhd,导入也不用加 --version,直接写:
code复制wsl --import Ubuntu D:\WSL\Ubuntu D:\wsl-backup\Ubuntu-backup.vhdx --vhd
导入完成后执行 wsl -l -v,你会看到 Ubuntu 后面出现 WSL 2 字样。再执行:
code复制wsl -d Ubuntu
如果能够正常进入 Ubuntu 的 shell 环境,说明文件系统已经成功导入。但到这里还没完,下一步很关键。
3.3 第三步:恢复默认用户并检查环境
不少人迁移完以后发现一个问题:进去成了 root 用户。这是因为 wsl --import 导入的发行版默认不记录原默认用户,每次都会以 root 身份启动。虽然 root 也能用,但原来那个账号的环境变量、自定义配置、SSH 密钥全都用不了,很别扭。
修复方法很简单。进入 Ubuntu 后,编辑 /etc/wsl.conf:
code复制sudo nano /etc/wsl.conf
如果没有这个文件就新建一个,写入:
code复制[user]
default=你的用户名
把 你的用户名 替换成迁移前的用户名。这一行的作用是指定进入 WSL 时默认切换为哪个用户。
保存后退出 Ubuntu,在 Windows 终端执行:
code复制wsl --terminate Ubuntu
这条命令会结束当前发行版运行实例。之所以要 terminate 而不是直接重新进入,是因为只有实例完全终止后,wsl.conf 里的配置才会在下次启动时生效。然后再次进入:
code复制wsl -d Ubuntu
现在你应该是原来的用户身份了。接着检查一下环境:
code复制whoami
pwd
ls -la
确认家目录文件都在,再执行 sudo systemctl status(新版 WSL 开启 systemd 的话)验证服务是否正常。另外建议检查网络:
code复制ping baidu.com
如果网络不通,多半是 DNS 配置问题,后面常见问题部分会说如何处理。
3.4 第四步:确认数据无误再清理旧系统
最重要的一条原则:在没有确认新实例一切正常之前,绝对不要删旧系统。
我先用几天新位置的 Ubuntu,日常开发工作基本都能正常运行,确认没有遗漏之后,才执行清理:
code复制wsl --unregister Ubuntu
这条命令会注销当前注册的 Ubuntu 发行版。注意:它同时也会删除与这个发行版关联的全部数据,包括位于 C 盘原位置的 vhdx 文件。所以执行前务必再想一遍:新位置的 Ubuntu 是否已经完全取代了旧位置的一切?
执行完可以再次查看:
code复制wsl -l -v
列表里已经没有 Ubuntu 了,C 盘空间也会明显释放。如果你执行 unregister 时新位置的 Ubuntu 还占着同样的名字,注册名其实已经被新位置占用了,不会影响新实例。放心清理即可。
提醒:如果以前使用
wsl --set-default Ubuntu把 Ubuntu 设为了默认发行版,迁移后建议重新执行一次这条命令,确保输入wsl时能直接进入 Ubuntu。
4. 迁移之后:系统优化与数据瘦身
4.1 用 .wslconfig 控制资源上限
迁移到新磁盘后,很多人会发现一个现象:WSL 里跑的进程对内存和 CPU 的占用有时不受控,Windows 主机反而变得卡顿。这是因为 WSL 2 默认会使用 Windows 可用的所有内存资源。虚拟机拿到多少资源,由 %UserProfile% 下的 .wslconfig 文件控制。
这个文件默认不存在,需要自己创建,位置是:
code复制C:\Users\<你的用户名>\.wslconfig
写入内容示例:
code复制[wsl2]
memory=4GB
processors=4
swap=8GB
配置说明:
memory:分配给 WSL 2 的最大内存,按你的机器配置调整,日常开发 4GB 到 8GB 足够。processors:允许 WSL 2 使用的 CPU 核心数。不配置的话会用满所有核。swap:交换分区大小,内存不够时的兜底。默认会自动分配,但显式指定更可控。
修改完这个文件后,同样执行 wsl --shutdown,然后重新进入 Ubuntu 才会生效。用 free -h 和 nproc 验证。
4.2 给 vhdx 做一次“瘦身”压缩
前面说过,虚拟磁盘不会因为删除文件而自动缩小。如果你迁移前数据已经比较大,导入后新生成的 vhdx 虽然比原来的干净一些,但仍然可能存在较大空洞。想彻底瘦身,操作步骤如下:
首先完全关闭 WSL:
code复制wsl --shutdown
然后打开 Windows 的磁盘管理工具。最直接的方式是运行 DiskPart,但 DiskPart 只能命令行操作。我之前更习惯用 Hyper-V 管理器,不过 Windows 家庭版不一定有。这里给一套 DiskPart 的完整流程:
code复制diskpart
进入 diskpart 交互环境后逐条执行:
code复制select vdisk file="D:\WSL\Ubuntu\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
attach vdisk readonly 表示只读挂载这个虚拟磁盘,这样压缩过程中不会被写入新数据。compact vdisk 是真正的瘦身操作,它会把未使用的空间从 vhdx 里释放掉。执行耗时取决于文件大小,几分钟到十几分钟都正常。完成后回到资源管理器查看文件大小,你会发现明显变小了。
如果你用的是 WSL 2 且版本较新,也可以直接在终端里执行:
code复制wsl --disk-manager
打开图形化磁盘管理界面操作,原理是一样的。
4.3 Docker Desktop 与项目目录的联动
很多人用 WSL 不只是为了开个终端,而是跑 Docker。Docker Desktop 默认使用 WSL 2 后端,容器镜像、卷数据都存在 WSL 发行版的虚拟磁盘里。这意味着迁移 Ubuntu 并不会让 Docker 的镜像自动搬走——Docker Desktop 用的是它自己注册的发行版(通常是 docker-desktop),不是你的 Ubuntu。
如果你只想搬 Ubuntu 上日常开发的数据,上面的流程就够用了。但如果想让 Docker Desktop 的镜像也换个位置,需要多一步:
打开 Docker Desktop,进入 Settings -> Resources -> Advanced,里面的 Disk image location 可以指定虚拟磁盘位置。改完之后 Docker 会重新生成一个新的发行版,镜像需要重新拉取或者通过导出导入方式迁移。
除了 Docker,还要注意项目文件的存放习惯。我见过有人习惯把代码放在 Windows 目录下,比如 D:\projects,然后通过 /mnt/d/projects 在 WSL 里访问。这样做的优点是 Windows 和 WSL 都能方便访问,但文件读写性能会打折。如果需要密集 IO 的操作(比如跑 npm install、编译大型项目),建议把项目放进 WSL 文件系统内部,比如 ~/projects,速度提升非常明显。迁移完这正好是个调整目录结构的契机。
5. 常见问题排查实录
5.1 先看速查表
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 导入后进入 root,原用户不见了 | import 不保留默认用户配置 | 修改 /etc/wsl.conf 的 [user] default,然后 wsl --terminate |
| wsl -l -v 显示两行同名 Ubuntu | 新旧发行版注册名冲突 | 确认新实例可用后 wsl --unregister 旧名 |
| Ubuntu 启动后没有网络,ping 不通 | DNS 或网络配置异常 | 修改 /etc/wsl.conf 加 [network] generateResolvConf=true,或检查 /etc/resolv.conf |
| 导出文件巨大,导入很慢 | 虚拟磁盘内有大量缓存和未回收空间 | 先 wsl --shutdown,再导出;导入后用 compact 压缩 |
| wsl --update 卡在“正在安装” | Windows 服务或虚拟机平台未启用 | 启用 Windows 功能中的“虚拟机平台”和“适用于 Linux 的 Windows 子系统”,重启后再更新 |
| 迁移后开始菜单的 Ubuntu 图标点不开 | 开始菜单快捷方式指向旧位置 | 直接重新固定 wsl -d Ubuntu 的快捷方式,或重新运行一次 ubuntu.exe |
| systemd 服务没有自动启动 | WSL 的 systemd 未开启 | /etc/wsl.conf 加 [boot] systemd=true,然后 wsl --shutdown 重启 |
5.2 导入后默认 root 的详细修复
这个问题太常见了,单独拿出来讲一次。wsl --import 的发行版默认没有默认用户概念,每次启动都是 root。如果你原来的所有个人配置都在普通用户下,操作步骤我已经在 3.3 节写过了,核心就两行:
code复制[user]
default=你的用户名
注意编辑完以后必须执行:
code复制wsl --terminate Ubuntu
然后再进。如果一直没有反应,检查一下 wsl.conf 的权限和位置,文件必须存放在 /etc/wsl.conf,不是家目录下。
5.3 导出/导入慢或失败排查
导出慢,绝大多数情况是虚拟磁盘文件大。一个 30 GB 的发行版导出需要一段时间,如果发现导出长时间不响应,先确认 wsl --shutdown 是否执行过。Windows 版本不新,WSL 进程没完全退出时导出会卡住或者报错。
另一种情况是导出路径所在磁盘空间不足。tar 格式的备份文件大约是原始 vhdx 的 0.8 到 1 倍大小,如果目标盘只剩几个 G,导出必然失败。可以先压缩 vhdx 再导出,或者用 --vhd 模式导出,速度更快,产物更小。
导入失败也常见。如果报错说“找不到指定的路径”,检查导入目录是否存在。有的版本不会自动创建 D:\WSL\Ubuntu 这个目录,需要提前手动建立。
5.4 服务无法启动或 wsl --update 卡住
很多人第一次接触 WSL 就遇到 wsl --install 太慢,或者 wsl --update 卡在某个百分比不动。这通常不是网络问题,而是 Windows 功能没有启用完整。
以管理员身份打开 PowerShell,执行:
code复制dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
两条命令分别启用 WSL 功能和虚拟机平台,执行完重启电脑,再更新 WSL。这个方法比设置里点击启用更彻底。如果提示“无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动”,大概率是没有开启虚拟机平台。
5.5 迁移后找不到原发行版快捷方式
迁移完以后,开始菜单里旧的 Ubuntu 快捷方式可能失效,双击没有反应。原因是商店版的快捷方式链接的是旧安装路径下的 ubuntu.exe。解决办法很简单,直接在终端里执行:
code复制wsl -d Ubuntu
能正常进入就说明系统没问题,快捷方式只是个摆设。重新固定一个指向 Windows Terminal 的快捷方式,或者用 wsl --set-default Ubuntu 保证输入 wsl 直接进入,比找旧图标更高效。
5.6 误删除旧系统后还能恢复吗
如果在新实例还没确认完全正常时就执行了 wsl --unregister,旧 vhdx 被删除是彻底性的,常规手段无法找回。这也是我反复强调先确认后清理的原因。万一真出现这种情况,还剩一个办法:检查之前有没有导出过备份文件。如果你在迁移过程中生成了 tar 备份且还没删除,可以直接再导入一次:
code复制wsl --import Ubuntu_restore D:\WSL\Ubuntu_restore D:\wsl-backup\Ubuntu-backup.tar --version 2
所以,导出的备份文件别删那么快。我习惯在迁移完成并正常使用一周后,才删掉备份文件。
最后分享几个实际使用中的习惯
迁移这种事情,最重要的不是命令背得多熟,而是每一步都给自己留后路。从 C 盘搬到 D 盘只是第一步,更好的做法是把未来的存储规划一起考虑进来。我现在的习惯是:系统盘只放 Windows 自身和开发工具,WSL 发行版统一放在 D:\WSL 下,Docker Desktop 的镜像数据指定到 D:\DockerData,项目的代码放在 WSL 文件系统内部或者专门的 E:\Projects 分区。这样即使以后 Windows 系统崩了要重装,所有开发环境的数据都不受影响,重新导入一遍备份就能无缝恢复。
另外一个经验是,定期给 WSL 做一次小检查。每个月看一次 vhdx 文件大小,如果发现和 Ubuntu 内实际使用量差距很大,就执行一次 wsl --shutdown,然后做磁盘压缩。别等到 C 盘弹红再处理,到时候想清理都费劲。
如果你按照这篇文章把 WSL 成功搬到了新磁盘,后面在 Ubuntu 里跑 CUDA、Docker 还是 Node.js,顺畅度通常都会有不小提升。磁盘空间一旦宽裕,整个 Windows 的运行都会更从容。
