装完WSL之后用了一两个月,C盘突然就爆红了,这种事情我身边已经有好几个人遇到过。原因不外乎那几样:Python虚拟环境、PyTorch的模型缓存、apt装了一堆依赖,再加上Docker镜像,WSL的虚拟磁盘文件就跟吹气球一样长到了几十个GB。再加上WSL本身默认装在C盘,Windows的临时文件、页面文件也都在C盘,最后的结果就是系统卡到怀疑人生。
我最初解决这个问题的办法很粗暴:直接卸载重装。但后来发现,WSL的发行版数据其实就是一个虚拟磁盘文件,把这块"硬盘"从C盘搬到其他盘,完全不需要重装系统,也不需要重新配置环境。整个过程十几分钟就能做完,而且还能顺手把WSL的虚拟磁盘压缩一遍,等于同时完成迁移和瘦身两件事。这篇文章就是把我的完整操作流程、踩过的坑和几个隐藏在细节里的知识点一起整理出来,照着做就能搞定。
注意:以下操作适用于WSL2。Windows 10(2004及以上)和Windows 11均可,命令在PowerShell中执行。
1. 先搞明白WSL的存储机制:C盘为什么会被吃干净
1.1 WSL的"系统盘"其实是一个文件
很多人对WSL有个误解,以为它像虚拟机一样会创建一个单独的分区。其实WSL2的整个Linux文件系统(包括/bin、/home、/usr下面所有东西)都存放在一个特殊格式的虚拟磁盘文件里,文件名一般是ext4.vhdx。
默认情况下,这个文件藏在当前用户的AppData目录里,具体路径是:
C:\Users\<你的用户名>\AppData\Local\Packages\<发行版包名>\LocalState\ext4.vhdx其中<发行版包名>对于Ubuntu来说通常是CanonicalGroupLimited.Ubuntu...这样的结构,不同版本略有差异。
也就是说,你在WSL里创建的文件、安装的软件包、Python环境、模型文件,本质上全都进了这一个文件里。Linux里的"磁盘占用"在Windows侧就表现为这一个文件的大小。理解了这一点,迁移思路就非常清晰了——我们要做的事,就是把整个ext4.vhdx的内容搬到D盘或者其他空间充足的位置,然后让WSL指向新的文件位置。
1.2 vhdx只增不减的膨胀逻辑
WSL2用的vhdx是动态扩展的虚拟磁盘格式。什么叫动态扩展?就是它一开始只有几百MB,随着你往里面写入数据,文件会逐渐变大。但问题在于:你在WSL里删除文件之后,vhdx文件并不会自动缩小。
我给打个比方:你往这个虚拟硬盘里塞了50GB的数据,后来删了30GB,但在Windows文件管理器里看,ext4.vhdx依然是50GB左右。那些被删除的数据块虽然在Linux视角下已经释放了,但虚拟磁盘文件本身不会把那部分空间交还给C盘。
这就是为什么很多人的C盘会被WSL慢慢吃干净——明明在WSL里df -h显示只用了20GB,但Windows侧的文件却占了60GB。
也正因为这个机制,手动重新导出再导入,相当于把数据重新打包成新的虚拟磁盘,那些空闲空间就会被剔除掉。所以迁移WSL和压缩WSL磁盘经常是同一个操作,一次搞定。
1.3 迁移的本质:导出tar再导入
WSL官方提供了两个命令,wsl --export和wsl --import,专门用于迁移和备份。它们的原理很简单:
wsl --export把整个Linux文件系统打包成一个tar文件(类似把整块硬盘做成镜像);wsl --import读取这个tar文件,在新的位置生成一个新的vhdx并注册到WSL。
这种做法有几个好处:迁移过程不依赖vhdx当前是否膨胀,打包出来的是实际数据;同时迁移后生成的vhdx按需增长,已经释放的空闲空间不会再占地方。无论你原来的vhdx被撑大到500GB还是800GB,只要其中实际数据只有40GB,导出的tar包也就是40GB左右,导入到新盘后新生成的vhdx同样在40GB左右。这一步对于被WSL磁盘膨胀困扰的人来说,简直就是一次免费的磁盘清理。
2. 迁移前的摸底:三个命令看清当前状态
不管做什么系统级的操作,我都习惯先摸清楚现状再动手。迁移WSL之前,用下面三个命令把当前的发行版信息和磁盘占用情况搞明白。
2.1 查看当前WSL发行版列表
在PowerShell中执行:
wsl --list --verbose或者用缩写形式:
wsl -l -v输出结果类似:
NAME STATE VERSION * Ubuntu Stopped 2这里NAME就是发行版名称(迁移的时候要用),VERSION必须要是2(也就是WSL2),否则后续的操作逻辑会有差异。如果显示的是1,建议先升级到WSL2再继续。
这一步别跳过。很多人迁移失败,就是因为连发行版名称都没确认,在导出的命令里写错名字,白白浪费了时间和流量。
2.2 找到当前vhdx文件的精准位置
在WSL里执行:
df -h /能看到Linux根目录挂载在哪个设备上,但那只是Linux视角。要找到Windows侧的物理文件位置,用文件资源管理器访问:
\\wsl$\<发行版名>\或者直接在PowerShell里这样定位:
Get-ChildItem -Path "$env:LOCALAPPDATA\Packages" -Filter "ext4.vhdx" -Recurse | Select-Object FullName, @{Name="SizeGB";Expression={[math]::Round($_.Length/1GB,2)}}这样能直接列出所有WSL发行版对应的vhdx文件路径和大小,一清二楚。我之前就因为装了多个发行版,搞混了哪个对应哪个,后来就是用这条命令彻底搞明白的。
2.3 评估目标盘空间和导出盘空间
迁移之前必须算一笔账:
- 目标盘(比如D盘)必须有足够空间容纳迁移后的新vhdx;
- 导出tar文件也需要一个临时位置,最好和目标盘在同一个盘符下,因为导出完之后如果确认没问题,tar包可以直接删掉,不会多占一份空间。
一般来说,目标盘的空闲空间至少要大于当前vhdx中实际数据量加上一部分余量。如果tar包本身就要放在目标盘,那么目标盘的空余空间至少要等于实际数据量的两倍(tar包一份+新vhdx一份)。实际数据量怎么看?在WSL里执行:
du -sh / --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/mnt这个值会比Windows侧看到的vhdx文件大小小很多,因为vhdx包含了膨胀的空闲空间。
3. 完整迁移流程:导出、注销、导入、恢复
下面的流程就是我在多次实践中觉得最稳妥的顺序。有人可能会想"先导入新的再删旧的",然而这样容易碰同名冲突的坑,所以我把推荐顺序排列如下:
3.1 第一步:关闭WSL,释放文件锁
wsl --shutdown这个命令会立刻终止所有正在运行的WSL发行版。这一步不能省,否则ext4.vhdx正在被占用,导出或者移动文件时会报权限错误。
执行完可以再跑一下wsl -l -v确认所有发行版都处于Stopped状态。如果你在WSL里还开着什么长驻服务,先手动保存一下数据,毕竟wsl --shutdown相当于直接断电关机的效果。
3.2 第二步:导出当前发行版为tar包
使用wsl --export命令导出。命令的基本格式:
wsl --export <发行版名称> <目标tar文件路径>举例,把名为Ubuntu的发行版导出到D盘的临时目录:
wsl --export Ubuntu D:\wsl-backup\ubuntu-backup.tar导出过程视数据量大小耗时从几分钟到几十分钟不等,过程中PowerShell窗口会一直处于繁忙状态,没有任何进度条,这是正常的,耐心等待就好。如果导出过程中报错,最大可能是目标路径不存在,或者磁盘空间不足。
这里有个小技巧:导出后的tar包其实就是一个完整的系统备份,所以即使你暂时不打算迁移,定期导出一次放在其他盘上,也算是一个保险措施。万一WSL哪天被弄坏了,用wsl --import分分钟恢复回来。
3.3 第三步:注销旧发行版
确认tar包导出完成且大小合理后,执行:
wsl --unregister Ubuntu注意,这一步需要谨慎操作。--unregister会删除该发行版在WSL中的注册信息,并删除关联的vhdx文件,也就是说你在WSL里的所有数据都会从C盘彻底移除。
所以要确保上一步导出的tar包是完好的,再执行这条命令。如果不放心,可以先看一眼tar包文件大小,再和WSL里du -sh的数据对比一下,数量级符合预期就基本没问题。
执行成功后,C盘的那一大块占用基本就释放出来了。
3.4 第四步:导入到目标盘
现在用wsl --import命令把tar包恢复到新的位置:
wsl --import <发行版名称> <目标安装目录> <tar包路径> --version 2举例,把之前导出的Ubuntu恢复到D盘:
wsl --import Ubuntu D:\WSL\Ubuntu D:\wsl-backup\ubuntu-backup.tar --version 2这里D:\WSL\Ubuntu是新的安装目录,导入后会在该目录下生成一个ext4.vhdx文件。如果这个目录不存在,命令会自动创建。
导入完成后,你可以在D:\WSL\Ubuntu\ext4.vhdx确认新vhdx文件的大小。这时候你会惊喜地发现,相比原来C盘上那个几十GB甚至上百GB的文件,新文件的体积明显小了一大截,这就是动态扩展磁盘重新整理之后的效果。
3.5 第五步:恢复默认用户
导入完成后直接启动WSL,会发现默认用户变成了root。这是wsl --import导入的常见副作用,因为tar包镜像虽然保留了原来的用户数据和权限,但WSL的默认用户配置不会跟着过来。
如果你用的是Ubuntu发行版,最简单的恢复方法是直接编辑WSL的配置文件。先启动WSL进入系统:
wsl -d Ubuntu然后在WSL内部执行:
echo -e "[user]\ndefault=<你的用户名>" | sudo tee /etc/wsl.conf把<你的用户名>替换成你原来在WSL里的用户名。写完退出WSL,再执行一次wsl --shutdown,重新进入就又变回原来的用户了。
如果不记得用户名,可以查看/home目录下有什么:
ls /home那里面基本就是你原来的用户名。
3.6 验证迁移结果
启动WSL后,挨个检查自己常用的环境是否正常:
- 确认Python环境还在:
python --version - 确认conda环境还在:
conda env list - 确认之前安装的软件服务能正常启动:
systemctl status或者直接尝试启动 - 确认文件数据都在:
ls ~
另外可以检查一下Windows侧新vhdx的位置和大小:
Get-ChildItem D:\WSL\Ubuntu\ext4.vhdx确认无误后,导出的tar包就可以删掉了。我个人习惯是留着它,等到新环境稳定运行一周后再删。这样万一迁移后有什么不兼容的地方,还有回滚的余地。
4. 迁移后的两个必做动作:清理残留和防止再次膨胀
迁移完成只是第一步,收尾工作做不好,过阵子又会陷入空间告急的循环。我总结了两个必做的收尾动作。
4.1 确认旧发行版空间真的释放了
正常情况下wsl --unregister会同时删除C盘上原来的ext4.vhdx文件。但这个文件有时候不会立刻消失,尤其是在Windows资源管理器还开着旧路径的时候。如果注销后C盘空间没有明显变化,建议这样排查:
Get-ChildItem -Path "$env:LOCALAPPDATA\Packages" -Filter "ext4.vhdx" -Recurse -ErrorAction SilentlyContinue如果还能看到残留的vhdx文件,说明删除没有完成。这时候手动删除即可,注意路径核对清楚,不要误删了其他发行版的文件。删除前最好重启一次WSL服务或者重启资源管理器,确保没有进程占用。
4.2 用diskpart压缩新盘的vhdx
迁移到新盘之后,vhdx一开始是"干净"的。但随着日常使用,它照样会膨胀。等你发现D:\WSL\Ubuntu\ext4.vhdx又变成好几十GB的时候,可以手动压缩一次。
WSL必须完全关闭:
wsl --shutdown然后以管理员身份打开PowerShell,进入diskpart:
diskpart在diskpart交互界面中依次输入:
select vdisk file="D:\WSL\Ubuntu\ext4.vhdx" attach vdisk readonly compact vdisk detach vdisk exit解释一下这几条命令的作用:
attach vdisk readonly:以只读方式挂载虚拟磁盘,这样可以在不启动WSL的情况下安全访问它;compact vdisk:这是核心命令,把虚拟磁盘中未使用的空闲空间回收掉,相当于给磁盘做了碎片整理和压缩;detach vdisk:解除挂载,确保操作完成后磁盘状态正常。
整个过程通常几十秒到几分钟。结束后再看vhdx文件大小,又能瘦下去一圈。我每过两三个月就会做一次这个操作,配合下面的日常清理,基本不会出现空间告急的情况。
4.3 顺手排查哪个目录最吃空间
迁移后正好是一起做系统"大扫除"的时机。登录WSL后,用du命令看看哪里占用最大:
du -h --max-depth=1 /home 2>/dev/null | sort -hr | head -20 du -h --max-depth=1 /usr 2>/dev/null | sort -hr | head -20如果你是重度用户,以下几个目录通常是大头:
~/.cache:pip、conda、apt的缓存,可能占好几个GB;~/.conda/pkgs:conda安装包缓存;/var/lib/docker:Docker的镜像和容器数据;~/.local/share/Trash:Linux图形环境下的回收站。
针对不同目录有对应的清理命令:
sudo apt clean sudo apt autoremove pip cache purge conda clean --all docker system prune -a这些清理命令在迁移后做一遍,能让新盘的vhdx保持在一个相当精简的状态。
5. 迁移过程中容易翻车的细节与排查思路
迁移流程看着就几条命令,但实际操作中总会遇到各种幺蛾子。我把亲身踩过的和帮别人排查时遇到过的几类高频问题列出来,方便你卡住的时候逐一对照。
5.1 导出失败:先看盘符路径和权限
我最早遇到的问题是wsl --export提示找不到路径。原因是PowerShell当前工作目录在C盘,而我把目标写成了相对路径。后来统一使用绝对路径就再没碰到过。
另一个常见问题是目标盘是U盘或者NAS网络驱动器,这种场合文件系统可能不支持大文件写入,或者写入速度极慢。如果遇到导出长时间卡住不动,先检查目标位置是不是NTFS格式,而且要有足够的连续空间。
5.2 导入后WSL里没有原来的用户
wsl --import导入后,默认进入的是root用户,而且经常出现/home/用户名下文件确实都在,但你不知道用什么命令切换到那个用户的情况。
我推荐的解决方案就是前面讲的/etc/wsl.conf配置法:
echo -e "[user]\ndefault=你的用户名" | sudo tee /etc/wsl.conf写完后重启WSL,默认用户就回来了。这个方法在Ubuntu、Debian、Kali等主流发型版上都通用,不用依赖发行版自带的exe命令。
5.3 迁移后网络异常:代理配置残留
如果你之前在WSL里配置过HTTP代理(比如给命令行工具加速用),迁移后可能会发现网络请求变慢甚至直接失败。
常见报错信息里会出现"detected localhost proxy configuration, but not mirrored to WSL"类似字样。这是因为Windows侧的代理设置和WSL2的NAT网络模式之间存在兼容性问题。
排查思路很直接:检查WSL里的环境变量:
env | grep -i proxy如果看到http_proxy、https_proxy之类的变量还指向旧的代理地址,要么更新为有效的代理端口,要么在/etc/wsl.conf中关闭相关配置,或者把Windows侧的代理设置暂时关闭,再重启WSL测试。
如果这个代理是业务必用的,推荐在Windows用户目录下创建一个.wslconfig文件,写入:
[wsl2] networkingMode=mirrored镜像网络模式下WSL会直接共享Windows的网络栈,比NAT模式少很多转发和隔离问题。不过需要Windows 11 22H2以上版本才支持,Windows 10用户就只能继续用NAT模式,遇到代理问题时手动调整WSL里的代理变量。
5.4 导入后磁盘空间比预期大很多
有朋友遇到过迁移后新vhdx居然还是几十GB,和原来几乎一样。这种情况通常不是迁移失败,而是因为tar包导入时保留了一些特殊的稀疏文件或者文件系统元数据。
解决方案是再做一次节4.2的vhdx压缩流程。如果压缩后还是很大,说明你的数据里确实有大量文件(比如大模型权重、数据集),那就属于正常情况了。这种时候更应该关注是否有必要把大文件单独放到Windows侧挂载目录(/mnt/d/...)来管理,避免写入WSL的虚拟磁盘。
6. 从根源上规避:新装场景还有其他更快的迁法
如果你还没开始用WSL,或者准备在另一台电脑上重新部署,下面两种方式也能达到目的,而且比导出导入更省事。
6.1 全新安装时直接指定目标盘
WSL默认安装在C盘,但新装的发行版可以在安装时指定位置。用wsl --install命令安装的发行版默认依然在C盘,不过你可以先安装,然后用前面导出导入的方法迁移。如果你不想走两遍流程,可以在应用商店安装发行版后,从设置里查看"移动"入口,部分发行版的后台应用支持直接移动到其他盘。
不过说实话,最快最可靠的方式还是老老实实"导出-注销-导入",这个方法对任何发行版都生效,不受应用商店的限制。
6.2 更高阶的直移法:--import-in-place
如果你的WSL版本比较新(WSL 1.2.0以上),还可以用--import-in-place参数,直接把现有的vhdx文件移动到新位置,然后注册。它的执行步骤是:
wsl --shutdown关闭所有实例;- 手动把整个发行版目录(包含
ext4.vhdx的那个文件夹)从C盘剪切到D盘; - 执行:
wsl --unregister Ubuntu wsl --import-in-place Ubuntu D:\WSL\Ubuntu这个方式比"导出再导入"快很多,因为它省掉了打包和重新生成vhdx的时间,只是把虚拟磁盘文件搬了个地方再重新注册。但注意它的弊端:没办法对vhdx做瘦身,原本膨胀的空间还会继续保留。如果C盘已经告急,单纯移动解决了位置问题,但磁盘空间的浪费依然存在。所以我的建议是:
- 如果只是腾位置,不在乎vhdx膨胀问题,优先用
--import-in-place,速度快; - 如果既想腾位置又想给虚拟磁盘瘦身,走完整的"导出-注销-导入"流程。
6.3 重度使用者的空间管理建议
迁移完成只是阶段性的胜利,如果继续无节制地往WSL里装东西,过几个月还是会把新盘塞满。我和WSL共处的这几年的经验是:
- 大数据文件尽量放到Windows侧访问,WSL里通过
/mnt/d/...直接引用,不要复制进WSL的虚拟磁盘; - Python和conda的缓存定期清理,尤其是经常测试新包的人,
~/.cache和conda的pkgs目录是最容易悄悄膨胀的地方; - 习惯性跟踪vhdx大小,在PowerShell里把查看
ext4.vhdx大小的命令存成一个别名,每次系统卡顿时顺手看一眼; - 每季度做一次
wsl --shutdown加compact vdisk的维护操作,整个过程不超过五分钟,但能保证虚拟磁盘长期处于合理大小。
按这套方法来管理,WSL的存储问题基本不会再成为你的困扰。迁移这件事真正麻烦的不是命令本身,而是对WSL存储模型的正确理解。搞清楚了ext4.vhdx就是一个会膨胀的虚拟磁盘文件,很多问题都能迎刃而解。我实操下来的总体感受是:尽早迁移、定期维护、把大数据隔离在WSL之外,这三件事做到,WSL用起来真的会省心非常多。