如果你也是那种C盘常年爆红、装个WSL没多久就发现Linux子系统已经吃掉几十个G的人,那这篇应该能帮你省下不少事。WSL(Windows Subsystem for Linux)说白了就是Windows里跑一个原生Linux内核环境,日常做开发、跑脚本、装工具链都挺方便,但它默认把所有虚拟磁盘文件都放在C盘用户目录下,时间一长文件系统镜像能涨到20GB甚至更多。把WSL迁移至非系统盘,是释放C盘空间最彻底也最省心的做法之一。这篇文章就完整记录一遍我把WSL从C盘迁到D盘的全过程,包含原理、命令、踩坑记录和迁移完之后的优化措施,适合所有被C盘空间困扰、想彻底把WSL发行版挪走的开发者参考。
1. 迁移前必读:WSL到底把东西放在哪
1.1 WSL2的虚拟磁盘机制
不少人对WSL的理解还停留在“Windows里装了个Linux文件夹”的阶段,实际上WSL2早就不是这个玩法了。WSL2底层是一个轻量级虚拟机,整个Linux根文件系统、安装的软件、用户数据、环境变量,全部打包在一个VHDX虚拟磁盘文件里。默认安装时,这个虚拟磁盘会被放到当前用户的本地应用数据目录里,路径长这样:
text复制C:\Users\<你的用户名>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu24.04LTS_xxx\LocalState\ext4.vhdx
不同发行版在Packages下的目录名不一样,Ubuntu、Debian、Kali各自的包名都不同,但结构基本类似。那个ext4.vhdx就是整个Linux系统的大本营,只要它还在C盘,你的C盘就永远不可能清爽。
这里要特别注意一个反直觉的现象:VHDX文件只增不减。你在WSL里删除文件、卸载软件,Windows侧看到的ext4.vhdx大小并不会明显缩小,因为虚拟磁盘内部释放的空间默认不会自动回收。所以哪怕你觉得自己“没装什么东西”,用久了这个文件照样可能膨胀到三四十个G。网上经常有人问为什么C盘空间越来越少,最后排查出来都是WSL的虚拟磁盘在偷偷“虚胖”。
1.2 为什么不能直接剪切文件夹
很多人第一反应是:“那我直接把整个Packages目录剪切到D盘不就行了?”听起来很直接,但实际操作会踩出一堆坑。
原因很简单:WSL发行版注册信息不在这个文件夹里,而是写在Windows注册表中。系统启动WSL时,会先读取注册表里登记的发行版名称、安装路径、BasePath等信息,然后按照注册表指向的位置去加载VHDX。你只剪切文件、不更新注册表,重新打开WSL时它还是去找原来的C盘路径,找不到就报错,或者更糟——系统在旧路径重新初始化一个全新的空白VHDX,看起来像数据全丢了。那种“明明文件还在但WSL里一片空白”的恐慌感,体验过一次就不想体验第二次。
另外,直接复制一个正在被占用的VHDX文件也有风险。如果WSL后台进程没完全退出,VHDX可能处于挂载状态,复制出来的文件本身就是损坏的,导入时大概率会报“an error occurred while running a wsl command”之类的错误。所以手工剪切复制这条路,不建议走。
我给三种常见方案做了个对比,看完你就明白为什么推荐官方导出导入:
| 迁移方式 | 是否推荐 | 优点 | 缺点 |
|---|---|---|---|
| 直接剪切/复制Packages目录 | 不推荐 | 操作简单、无需命令 | 注册表未更新、VHDX易损坏、版本升级后目录名会变 |
| 第三方工具(如LxRunOffline) | 不推荐 | 功能多、支持改路径 | 额外依赖、兼容性风险、遇到WSL大版本更新容易失灵 |
| 官方wsl --export / --import | 强烈推荐 | 微软原生支持、稳定可靠、可顺带备份 | 需要执行几条命令,但都有固定套路 |
1.3 迁移方案选型:为什么用官方导出导入
现在WSL迁移最靠谱的方案,就是官方提供的wsl --export和wsl --import命令组合。整体思路分三步:先把WSL发行版导出成一个tar包,然后从Windows注销掉这个发行版,最后重新导入到非系统盘的指定目录。
这个方案的第一个好处是“轻”。它不用手动去碰VHDX文件,也不会动Windows注册表里那些复杂的键值,所有迁移逻辑都由WSL服务自己完成,版本兼容性最好。第二个好处是“顺”。导出过程等于给你整个Linux环境做了一次完整快照,万一迁移后出问题,保留的tar包还能随时再导入回去,相当于顺便做了一次备份。第三个好处是“净”。新导入时系统会重新生成一个VHDX文件,体积是以当前实际内容为准的,之前在C盘那个“虚胖”的虚拟磁盘等于被自然压缩了一轮。
我在决定迁移之前也犹豫过要不要用第三方工具,毕竟网上教程多、看起来一键搞定。但考虑到这些工具在Windows 11新版本下偶尔会有兼容坑,而且官方命令本身就没几条,最后还是老老实实走正统路线。事实证明,官方方案虽然看起来“土”,但胜在稳。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 准备好了再动手:迁移前必须检查的三件事
2.1 确认发行版信息和WSL版本
迁移前先要搞清楚自己机器上到底装了哪些发行版,以及它们跑的是WSL1还是WSL2。这一步别跳过,后面很多操作都和这个有关。
打开PowerShell或Windows Terminal,执行:
powershell复制wsl -l -v
输出大概长这样:
text复制 NAME STATE VERSION
* Ubuntu-24.04 Running 2
看NAME列确认发行版名称,这个名称后面导出导入都要用,拼写必须完全一致。VERSION列如果是2,说明走的是WSL2虚拟化方案,迁移过程没有任何问题;如果显示1,迁移也能做,但建议先把WSL版本升级到2。可以顺手执行一下wsl --update,把WSL本体更新到最新版本,避免因为版本过旧导致某些命令和参数不识别。
很多人的报错“wsl --install太慢”或者“wsl --install已禁止403”,本质上都跟下载环节有关,要么是网络问题,要么是旧版本残留导致的异常。我的建议是:如果遇到这类问题,先不要死磕install,直接把WSL版本升到最新,很多莫名其妙的问题就消失了。
2.2 目标盘选择和目录规划
目标盘看起来是个小问题,实际上决定了迁移完之后的体验,这里有几个硬指标:
- 必须是非系统盘分区,格式必须是NTFS。FAT32和exFAT都不行,因为WSL2的VHDX文件需要支持文件权限和符号链接,NTFS是底线。
- 目标盘剩余空间建议是“当前WSL占用空间的两倍以上”。因为导出出来的tar包和实际VHDX大小基本相当,导入过程中还需要临时空间,如果空间不够,导入到一半失败是最尴尬的。
- 安装路径不要带空格,不要放在OneDrive同步目录里,也不建议直接扔在某个U盘或移动硬盘上用。虽然技术上能跑,但跨设备移动存储很容易出现文件锁、挂载失败之类的诡异问题。
我最终选择的目录结构是这样的:
text复制D:\WSL\Ubuntu-24.04\
这个路径有两点好处:一是统一管理,以后无论装几个发行版,都放在D:\WSL\下面,每个发行版一个子目录,一眼就能看明白;二是路径短、无空格,导入导出命令写起来不容易出错,也方便后期用脚本批量处理。
在动手之前,先用下面这条命令看一下WSL内部到底占了多少空间:
bash复制wsl -d Ubuntu-24.04 -- sh -c "df -h / && du -sh /root /home 2>/dev/null"
同时在Windows侧看一眼ext4.vhdx的实际大小,两者对比就能估算出导出包的大小。如果你发现内部占用只有10G但vhdx文件有30G,那就说明虚拟磁盘确实“虚胖”了,迁移之后还能白赚一波瘦身。
2.3 做好备份再操作,别怕多花几分钟
迁移本身不算高风险操作,但保险起见,我还是建议在动手前给重要数据再加一道保险。导出tar包是文件级快照,能保证系统层面的完整性,但如果你WSL里跑着数据库、Docker容器,或者有未提交的代码,最好先在里面做一次应用层备份。
常见的备份动作包括:用mysqldump导数据库、把未提交的Git仓库git push到远程、用docker commit把重要容器提交成镜像。这些都是几分钟的事,但能避免“系统迁移成功了,可数据在迁移前就已经坏了”这种无法挽回的情况。
另外还有一个很容易忽略的点:迁移前把WSL里的所有会话都退出干净。不只是关掉终端窗口,还要检查有没有VS Code远程窗口、Docker Desktop、PyCharm这类还连着WSL的进程,因为它们在后台可能还占用着发行版文件句柄。最稳妥的办法是下一步先执行关停命令,再确认一遍没有残留进程。
3. 实操:WSL迁移至非系统盘完整步骤
3.1 第一步:彻底关闭WSL
这一步的核心命令是:
powershell复制wsl --shutdown
这条命令会立刻停止所有正在运行的WSL发行版和轻量级虚拟机。Windows 11上如果你开过Docker Desktop,它依赖的WSL2后端也会一起停掉,这是正常现象,后面重新启动发行版时会自动恢复。
执行完wsl --shutdown之后,我建议再执行一条检查命令:
powershell复制wsl -l --running
如果输出是“没有正在运行的发行版”,说明WSL已经完全退出了。这里别偷懒,我见过有人没退出WSL就直接做导出,结果导出的tar包在重新导入时报文件系统错误,最后只能重新导出一遍,白白浪费一次等待时间。
3.2 第二步:导出发行版为tar包
WSL迁移的核心操作就是导出,命令如下:
powershell复制wsl --export Ubuntu-24.04 D:\backups\wsl-ubuntu-2404.tar
等号前面的Ubuntu-24.04必须是wsl -l -v里查到的发行版名称,后面是你想存放tar包的路径。导出过程根据系统大小需要几分钟到十几分钟不等,期间不要关窗口,也不要再启动任何WSL发行版。
这里有两个实用技巧可以分享。第一,如果你不急着马上迁移,只是想先做个备份,导出的tar包放心留着,它就是一份完整的系统镜像,理论上可以随时导入到任意一台装了WSL的机器上恢复环境。第二,tar包体积可能很大,如果是跨电脑传输或者硬盘空间紧,可以手动用gzip压一下,把导出文件变成tar.gz:
powershell复制gzip D:\backups\wsl-ubuntu-2404.tar
后面导入的时候,wsl --import能直接识别gzip压缩格式,不用解压再导入。
顺便说一句,新版WSL也支持wsl --export直接把发行版导出成vhdx文件(加--vhd参数),但日常迁移场景还是用默认的tar格式最通用,兼容性也最好。
3.3 第三步:注销旧发行版
确认导出的tar包完整生成后,下一步是注销C盘上的旧发行版:
powershell复制wsl --unregister Ubuntu-24.04
注意,这条命令会彻底删除注册表里的发行版信息和对应的VHDX文件,相当于把这个发行版从WSL里“抹掉”。如果你导出过程出过问题,或者tar文件不在安全位置,就先不要执行这步。虽然理论上还能再安装回来,但重新配置一遍环境的痛苦没必要体验。
执行完之后再用wsl -l -v确认,列表里已经看不到Ubuntu-24.04了。这时候回到C盘对应目录看一眼,ext4.vhdx文件应该已经被清理掉,这部分空间就是实打实释放出来的。
3.4 第四步:导入到非系统盘
注销旧发行版之后,我们重新把发行版注册回来,只不过这次指定到D盘:
powershell复制wsl --import Ubuntu-24.04 D:\WSL\Ubuntu-24.04 D:\backups\wsl-ubuntu-2404.tar --version 2
命令参数解释一下:第一个Ubuntu-24.04是导入后的发行版名称,可以跟原来保持一致,也可以改成你想要的新名字;D:\WSL\Ubuntu-24.04是新的安装目录,系统会自动生成ext4.vhdx;D:\backups\wsl-ubuntu-2404.tar是刚才导出的tar包路径;--version 2指定用WSL2模式运行。
导入过程没有进度条,可能要等几分钟。完成后执行:
powershell复制wsl -l -v
看到Ubuntu-24.04的状态是Stopped、版本是2,迁移基本就成功了。再运行wsl -d Ubuntu-24.04试试进入系统,执行一下ls、python --version这类命令,确认基本环境没问题,就可以把备份的tar包删掉了。
3.5 第五步:恢复默认用户
这一步是很多第一次迁移的人最容易踩坑的地方,因为通过wsl --import导入的发行版,默认用户会被重置为root,运行wsl -d Ubuntu-24.04直接进的就是root身份,并不会自动切换回你之前的那个普通用户。
恢复方法不复杂。先用root身份进入WSL:
powershell复制wsl -d Ubuntu-24.04 -u root
然后编辑WSL的配置文件/etc/wsl.conf,如果没有这个文件就新建一个:
bash复制vi /etc/wsl.conf
加入下面两行内容:
ini复制[user]
default=你的用户名
保存退出后,在Windows侧执行:
powershell复制wsl --terminate Ubuntu-24.04
重新进入WSL,就会以你指定的普通用户身份登录了。需要注意,/etc/wsl.conf里如果之前已经有过[user]段落,直接修改default=那行就行,不要重复追加,不然后写的配置可能不生效。
3.6 第六步:清理与最终验证
迁移完成后不要急着收工,我习惯按下面这个清单过一遍:
- 确认C盘旧目录里的ext4.vhdx已删除,没有残留空壳文件夹
- 用
df -h检查WSL内部根分区空间,确认数据完整 - 执行
sudo apt update验证包管理器正常 - 打开之前用过的服务,比如数据库、Docker,确认都能正常启动
- 检查默认用户是不是已经恢复成普通用户
- 确认文件权限、符号链接这类Linux特性没有异常
全部通过之后,再确认预留空间的占用情况。如果目标是释放C盘,可以对比一下迁移前后的C盘剩余空间变化。如果C盘空间还是紧张,可能还需要考虑虚拟内存pagefile.sys的转移,那是另一个任务,不过WSL这个大块头挪走之后,大部分人的C盘压力已经能缓解一大半了。
4. 常见问题与排查实录
4.1 导入后默认用户变成root,切换不回去
前面已经说了主要原因:WSL原装安装会在首次启动时创建一个跟Windows用户名相同的普通用户,并且把该用户设为默认;但通过wsl --import导入的tar包,注册信息里不会保留“默认用户”这个状态,所以系统退回到root兜底。
解决方案就是修改/etc/wsl.conf里的[user] default=配置。注意修改完一定要执行wsl --terminate让发行版完全停止,然后再重新进入。如果只是关闭终端窗口,WSL后台进程可能还活着,配置不会立刻生效。
4.2 导入时报错“an error occurred while running a wsl command”
这个报错属于WSL的通用错误,原因五花八门,我遇到过三类情况。第一种是导出时WSL没有完全关闭,导出的镜像文件本身不完整,处理办法是重新执行wsl --shutdown后再导出一次。第二种是目标盘空间不足,导入过程中虚拟磁盘创建失败,清理空间后重试即可。第三种是WSL服务版本过旧,对新格式的tar包支持不好,升级wsl --update后问题就消失了。
如果报错信息里还带着please check your wsl config字样,可以检查一下%UserProfile%\.wslconfig文件,里面如果写了不合理的配置项(比如内存超出物理内存),留在那里会影响所有发行版的启动。实在排查不出来,执行wsl --shutdown之后重启电脑,大部分临时性错误都能解决。
4.3 VHDX文件迁完后仍然越来越大
很多人以为迁移到D盘之后就一劳永逸了,其实不是。虚拟磁盘“只增不减”的特性在新盘上依然存在,只是不再占用C盘了。如果你在WSL里频繁安装卸载软件、拉取Docker镜像,ext4.vhdx还是会慢慢膨胀。
处理办法是定期压缩虚拟磁盘。先执行wsl --shutdown,然后在PowerShell里执行:
powershell复制diskpart
进入diskpart交互界面后依次执行:
text复制select vdisk file="D:\WSL\Ubuntu-24.04\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
压缩前建议先在WSL内部做一轮清理,把包管理器缓存、旧内核、无用Docker镜像都清一遍,这样压缩效果才明显。我实测过一次,清理前vhdx是30G,压缩后降到8G,效果非常可观。这也是为什么迁移之后,我愿意专门花时间把这些优化动作做一遍。
4.4 WSL启动后提示某个目录无法访问
迁移后偶发会遇到这样的问题:wsl命令能进,但工作目录卡在一个Windows路径下提示找不到目录。这类问题主要出在旧会话记住了迁移前的路径,比如原来默认工作目录是某个C盘路径,迁移后该路径并不存在。解决办法很简单,启动后先执行cd ~切到Linux家目录,或者在.bashrc里显式配置一个固定的启动目录。
如果你的开发环境依赖VS Code的WSL远程扩展,迁移后第一次打开项目时如果提示“无法解析工作目录”,关掉VS Code的所有窗口重新打开一次,让远程WSL重新建立会话,通常就能恢复正常。
4.5 常见问题速查表
| 问题现象 | 可能原因 | 处理操作 |
|---|---|---|
| 导入后默认用户是root | 导入不保留默认用户映射 | 修改/etc/wsl.conf,设置[user] default |
| import报错无法创建VHDX | 目标盘空间不足 | 清理空间或换更大的分区 |
| tar包导出过程卡住 | WSL未完全关闭或磁盘IO慢 | 先wsl --shutdown,等磁盘空闲再导出 |
| 迁移后WSL里中文/编码异常 | 环境变量缺失 | 重新设置LANG、LC_ALL等变量 |
| 新盘vhdx持续膨胀 | Linux内部删除文件不回收 | 定期清理内部缓存后用diskpart压缩 |
| 启动提示找不到Windows路径 | 旧会话残留路径 | 进入后cd ~,重启VS Code或终端 |
| Docker Desktop无法启动 | WSL停止后Docker守护进程未恢复 | 执行wsl --shutdown后重启Docker Desktop |
| distro启动后没有systemd | WSL版本过旧或未开启Systemd | 检查.wslconfig,确认systemd=true |
5. 迁移后的进阶整理与扩展
5.1 给虚拟磁盘写一个“瘦身脚本”
既然已经体验过VHDX虚胖的坑,那就不建议再手动清理了,完全可以把这个动作用PowerShell脚本固化下来。我现在的做法是写一个compact-wsl.ps1,每次需要瘦身时直接以管理员身份运行:
powershell复制wsl --shutdown
diskpart /s D:\scripts\compact-wsl.txt
对应的compact-wsl.txt里写:
text复制select vdisk file="D:\WSL\Ubuntu-24.04\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
脚本虽简单,但非常实用。另外我习惯先在WSL里跑一轮清理命令再执行脚本,效果会好很多:
bash复制sudo apt clean
sudo apt autoremove -y
docker system prune -af --volumes 2>/dev/null
这两步配合起来,磁盘占用基本能被压到最小。整个过程中最容易被忽略的是:脚本运行期间一定不要打开任何WSL发行版,也尽量不要运行Docker Desktop,否则wsl --shutdown根本关不干净,diskpart会提示VHDX正被占用。
5.2 规划多发行版的统一存放目录
如果你以后还想再装第二个发行版,建议直接沿用D:\WSL\这个统一目录。以后无论是正常安装还是离线安装,都让所有Linux子系统的虚拟磁盘待在同一个盘符下,既方便统一备份,也方便一次性排除C盘问题。
很多人的WSL发行版是通过wsl --install -d Ubuntu-24.04装到C盘的,装完再迁移多少有点折腾。如果提前决定要把WSL整体放D盘,可以绕开这个流程:下载发行版对应的rootfs tar包,直接wsl --import导入到D盘指定目录,效果跟官方安装几乎没有区别,而且省去“装完再迁移”的多余步骤。
我在日常使用中还发现,把WSL统一放在非系统盘之后,重启电脑后启动速度反而比之前在C盘更稳,这可能是因为系统盘IO繁忙时WSL虚拟磁盘可以减少排队等待。当然这个体验因人而异,但放在非系统盘对C盘碎片化也有好处,整体收益是正的。
5.3 开发工具联动配置也别忘了
WSL迁移完,开发工具侧的一些指向也要顺手检查一下。VS Code如果装了Remote-WSL扩展,迁移后第一次打开项目时会自动检测到新的WSL环境,重新建立连接后就能正常用。PyCharm那边如果之前配置过WSL解释器,需要到解释器设置里重新确认路径,因为解释器的Linux路径没变,但Windows侧映射路径变了。
有些工具链和数据目录也需要调整。比如Docker Desktop如果选择“Use WSL 2 based engine”,它默认也会把大量镜像数据放在系统盘的用户目录下,时间长了又是几个G的占用。迁移思路跟本文类似,把Docker的数据目录指向D盘,然后把原来的数据清掉,这块能再释放不少空间。另外,如果你习惯在WSL里跑binwalk、CUDA这类重量级工具,迁移后不需要做任何调整,因为它们都运行在Linux侧,跟VHDX在哪个盘没有关系。
5.4 迁移备份的“一鱼多吃”
整个export/import流程熟练之后,你等于掌握了一套完整的“WSL环境搬家”技能。它不只能做磁盘迁移,还能用来复制开发环境:在一台机器上把WSL导出成tar包,拷贝到另一台电脑上导入,几分钟就能得到一个完全一致的Linux开发环境,比自己手动配置依赖高效得多。
我也试过配合tar包做系统级回滚。有时候在WSL里折腾内核或系统库,改坏了导致环境起不来,直接从之前导出的tar包重新导入一次,比在Linux里费劲修复快多了。当然前提是你有定期导出的习惯,把这个当成WSL的“系统还原点”,用起来非常顺手。
我个人在实际操作中的体会是:迁移WSL真心不算复杂,最花时间的反而是迁移前的数据梳理和迁移后的工具链验证。只要稳住顺序,先导出、再注销、再导入,中间不乱插操作,基本不会出大问题。如果你也想给C盘减负,或者正好要给新电脑搭一套一模一样的Linux开发环境,照着这套流程走一遍,应该能少踩不少坑。最后再分享一个小技巧:迁移完先别急着删tar包,留着它用几天,等确认所有工作流都正常再清理,心里踏实得多。
