上周把用了三年的 500G 系统盘换成 2T 的 NVMe,Windows 那边其实只花了不到四十分钟——用系统迁移工具点几下,数据拷完修一下引导就起来了。真正让我熬到凌晨两点的是 WSL2 里那套跑了两年多的开发环境:Ubuntu 22.04 装着 Python 工具链、几个 Conda 环境、Docker 的镜像和卷、一堆 SSH 密钥和配置文件,还有一个 40 多 G 的 CUDA 训练环境。这些东西在 Windows 的“系统迁移”逻辑里是隐形的,因为它藏在ext4.vhdx这个虚拟磁盘文件里,跟着整盘克隆走很可能直接把环境弄脏甚至弄坏。所以我最后选择的路线是:Windows 侧走常规迁移,WSL2 侧走export+import的显式搬家,把“哪些要带走、哪些要重建”这件事彻底想清楚。这篇文章就是这次完整过程的记录,从迁移前的资产盘点到新盘底座的搭建、发行版打包搬运、工具链恢复,一直到踩过的坑和排查表。不管你是换大容量 SSD、重装系统后想复原环境,还是单纯想把 WSL2 从 C 盘挪到数据盘,里面这些步骤基本可以直接抄。
1. 动手前先把“要搬什么”列成清单
换盘这件事最容易被低估的地方,不是技术难度,而是范围界定。很多人一上来就打开迁移工具,结果搬完才发现少了两三个不起眼但很关键的东西。我在旧盘上花了一个多小时做盘点,事后证明这一个小时省了至少半天的返工。
1.1 本次迁移涉及的三层资产
我把它拆成三层来看,每层的迁移方式和风险完全不同。
第一层是Windows 本体和授权。系统、驱动、激活状态、Office 之类的授权绑定,这层是最适合“原地平移”的,也就是用系统迁移类工具把整个分区克隆过去,让 Windows 觉得自己还在原来那块盘上。这层的风险主要来自引导方式和盘符变化。
第二层是Windows 上的用户数据与软件配置。文档、下载、桌面、浏览器书签与登录态、终端配置、开发工具的 Windows 侧组件(比如 VS Code、Docker Desktop 本体)。这层用文件复制就够了,不需要克隆。
第三层就是WSL2 发行版,也是这次的主角。它本质上是一个装在%LOCALAPPDATA%\Packages\<发行版包名>\LocalState\ext4.vhdx里的 ext4 虚拟磁盘,里面是一个完整的 Linux 根文件系统,包含 home 目录、已安装的包、环境变量、systemd 服务、crontab、SSH 密钥、Docker 卷等等。这层不能用文件复制的方式搬,因为它正在被 WSL 挂载使用,直接拷贝 vhdx 得到的是一个状态可能不一致的文件,轻则文件系统要 fsck,重则直接损坏。
除了这三层,还有一批“散落在外”的东西经常被漏掉:
C:\Users\你的用户名\.wslconfig,这是 WSL2 的全局资源配置文件,不重建的话内存、CPU、交换分区全回到默认值。- Windows 注册表里的
HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss,记录了发行版的注册信息、默认发行版、默认用户等,可以做参考但要谨慎导入。 - Docker Desktop 的
settings.json,里面存着镜像加速地址、WSL 集成开关、资源分配策略。 - VS Code 的 Remote-WSL 扩展和它记录的最近打开目录,不影响功能但重建起来挺烦。
提示:盘点阶段建议直接开一个纯文本文件,逐条写“这个名字 + 从哪来 + 怎么恢复”,不要靠脑子记。我当时的清单有 27 条,最后真正需要手动重建的有 5 条,其余全是复制粘贴。
1.2 为什么我不建议直接对整盘做克隆了事
先说明立场:整盘克隆或者分区迁移这类操作本身是成熟可靠的,我用过不止一次,重装系统时它确实是最省事的路子。但涉及 WSL2 的时候,直接克隆会引入几个具体问题,值得单独拿出来讲清楚。
一是文件状态一致性。克隆工具工作时,Windows 能识别ext4.vhdx这个文件,但它不知道里面是一个正在被 Linux 内核写入的文件系统。如果你在做迁移时没有先执行wsl --shutdown,WSL2 的后台进程、systemd 服务、数据库进程可能正在往 vhdx 里写数据。克隆出来的副本可能包含了写了一半的日志或者不一致的元数据。Linux 的 ext4 有 journal 能在挂载时回放,但这个回放能修好多少完全看运气,我见过恢复完文件都在但权限全乱的情况。
二是稀疏文件被展平。ext4.vhdx默认是动态扩展的稀疏文件,声明容量可能 1TB,实际占用只有 60G。有些迁移工具不理解 VHDX 的语义,会按声明容量读取,导致目标盘瞬间被吃掉几百 G 甚至直接写满。我在第一次尝试时就遇到过:目标盘只剩 300G,工具报告需要写入 1.05TB,直接卡死。
三是“历史包袱”被原样带走。整盘克隆会把旧系统里所有的临时文件、日志、孤儿包、错误配置一并搬过去。三年积累下来这些东西少说几十个 G,而且它们往往就是之后各种诡异问题的源头。相比之下,全新安装加显式恢复,等于强迫自己做一次清理。
四是盘符和挂载点的连锁反应。WSL2 访问 Windows 文件是通过/mnt/c、/mnt/d这种自动挂载点。如果新盘的分区布局和旧盘不一样,比如原来 E 盘是数据盘,新机器上变成了 D 盘,那你所有脚本里写死的路径全要改。这个问题在换盘时非常普遍。
1.3 迁移顺序:先 Windows 落地,再重建 WSL2
顺序上只有一种合理选择:Windows 先完成迁移或重装并正常开机,接着安装 WSL 组件和内核,最后再导入发行版。原因很直接,wsl --import这个命令依赖 WSL 的服务组件、虚拟化平台功能和内核更新包已经在位,在一个还没装过 WSL 的干净系统上,你连wsl这个命令都调不出来。
具体的时间安排我建议是这样:提前一到两天在旧系统上完成导出和全量备份;换盘当天只做 Windows 侧的迁移,跑通开机、驱动、网络、激活;第二天再慢慢处理 WSL2 和工具链。把两件事塞在同一天,一旦 WSL 那边出问题,你在一个“旧盘已经拆掉、新系统还没配好”的状态下排查,心态会崩。
2. 新盘上的 Windows 与 WSL2 底座搭建
这一段是整个流程的地基。地基没打好,后面导入的发行版会有各种奇怪的毛病,而且排查起来特别费劲,因为你不确定问题出在发行版本身还是底层的 WSL 组件。
2.1 旧盘数据的三层备份
备份这件事我要强调一点:不要把 WSL2 的备份和 Windows 的备份混在一起做。它们的验证方式、还原方式、失败后果都不一样,混在一起出问题时会互相牵连。
我的做法是物理隔离,用三块不同的移动硬盘或者至少三个不同的目录:
第一块放 Windows 侧的文件级备份,直接用资源管理器拖或者用robocopy做增量。robocopy在处理长路径和大量小文件时比资源管理器可靠得多,命令大概是robocopy "E:\" "F:\backup\win" /MIR /R:1 /W:1 /MT:16 /XJ,其中/XJ是跳过符号链接,在 Linux 文件名通过 WSL 映射出来时特别重要。
第二块放 WSL2 发行版的导出文件。做法是先关掉所有 WSL 实例再导出:
# 在 Windows 侧的 PowerShell 里执行 wsl --list --verbose wsl --shutdown wsl --export Ubuntu-22.04 D:\wsl-backup\ubuntu2204-20240601.tarwsl --shutdown这一步不能省,它保证导出时文件系统是静止的。导出的 tar 里包含整个根文件系统,包括/home、/etc、/usr、/var,但不包含/mnt下的 Windows 挂载,也不包含 WSL 在 Windows 侧注册表里的元数据。如果你的 WSL 版本比较新,还可以用wsl --export --vhd直接导出一个 vhdx 文件,速度快很多,因为省掉了打包成 tar 的过程,代价是文件体积更大。我那次 Ubuntu 环境实际占用 58G,tar 导出后 41G,vhdx 方式导出是 62G。考虑到后面还要拷贝,我选了 tar。
第三块放“零散配置”:.wslconfig、Docker 的settings.json、终端配置、~/.ssh密钥单独加密压缩一份。密钥这种东西我习惯单独放,因为它的丢失成本最高且无法通过重装恢复。
2.2 Windows 侧迁移方案怎么选
Windows 本体怎么搬,这个选择会直接影响后面 WSL2 的状态,所以值得展开对比。
| 方案 | 原理 | 优点 | 风险与适用场景 |
|---|---|---|---|
| 系统迁移工具(分区助手、DiskGenius 等) | 克隆系统分区到新盘并修复引导 | 快,软件和授权全保留 | 会带走旧系统的冗余;WSL 的 vhdx 会被一起克隆,需提前处理 |
| 全新安装 Windows | 重装后重新装软件 | 干净,问题少 | 耗时;需要重新激活和配置 |
| 镜像备份还原 | 用系统镜像工具整盘还原 | 完整还原到任意盘 | 对新盘容量有要求;同样会带上 vhdx |
我最终选了第一种加第三种混合:用工具把系统分区迁到新 NVMe,让 Windows 和 Office 的激活状态原样保留,同时把 WSL 的ext4.vhdx排除在迁移范围之外(在迁移工具的分区选择里把它跳掉,或者迁移完成后手动删除目标盘上的 vhdx,改用导入的方式重建)。这样既省了重装系统的时间,又避开了 vhdx 被克隆带来的隐患。
关于耗时,给个参考数字。500G 的数据,SATA 固态顺序读写大约 500MB/s,理论下限 16 分钟,实际因为小文件多、校验开销,跑 40 到 90 分钟都正常。NVMe 到 NVMe 的顺序读写能到 3000MB/s 以上,但迁移工具往往是单线程或者受限于目标盘写入带宽,实测下来 500G 大约 20 到 30 分钟。真正拖慢速度的是那种几十万个几 KB 小文件的目录,比如node_modules和 Conda 的pkgs缓存,这种场景下顺序带宽根本用不上。
注意:迁移前务必确认新盘的接口和协议,M.2 插槽有的是 PCIe 3.0 x4,有的是 4.0 x4,还有少数走 SATA 通道。把一块 PCIe 4.0 的盘插在只支持 3.0 的槽上能用,但速度会砍半。这个过程不需要额外操作,插上就能跑,只是心里要有预期。
2.3 启用 WSL2 的前置条件与虚拟化检查
Windows 落地之后,安装 WSL2 之前有一项检查必须做:虚拟化是否开启。WSL2 本质上是跑在 Hyper-V 虚拟化平台上的轻量虚拟机,没有硬件虚拟化支持它根本起不来,最常见的报错就是“因为此计算机上未启用虚拟化,请确保计算机固件设置中虚拟机平台已启用”。
检查方法有三个层次,我一般按顺序做:
第一层,任务管理器 → 性能 → CPU,右下角看“虚拟化”那一项是不是“已启用”。这是最快的方式。
第二层,命令行systeminfo,看输出的最后几行有没有 Hyper-V 相关信息。或者在 PowerShell 里跑Get-ComputerInfo -Property HyperV*。
第三层,如果前两层显示未启用,就进 BIOS/UEFI 设置找虚拟化选项。Intel 平台叫 Intel VT-x 或者 Intel Virtualization Technology,AMD 平台通常叫 SVM Mode。有些主板的选项藏在“高级 → CPU 配置”下面,有些在“超频/性能”菜单里,找起来比较费劲。同时如果 BIOS 里有 “VT-d” 或者 “IOMMU”,一般也建议一起打开。
BIOS 改完之后,接着启用两个 Windows 功能:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart这两条命令执行完需要重启一次。重启后把 WSL 内核更新包装上,然后设置默认版本:
wsl --update wsl --set-default-version 2第一层和第二层检查有个坑:如果 BIOS 里虚拟化是开的,但任务管理器里显示“已禁用”,那大概率是 Hyper-V 相关的功能没装全,或者被其他虚拟化软件占用了。这种情况不是硬件问题,而是软件层面的冲突,后面第 5 章会专门讲。
2.4 发行版版本怎么选
新机器上装哪个版本,取决于你要恢复的环境原本是什么。wsl --list --online可以列出所有可在线安装的发行版。
Ubuntu 20.04 目前处于生命周期的后半段,标准支持已经结束,继续用主要是为了兼容某些只支持旧 glibc 的老项目。22.04 LTS 是我最推荐的默认选择:软件源活跃,CUDA 和主流框架支持完整,社区资料多,出问题好搜。24.04 LTS 版本更新,glibc 到了 2.39,Python 默认是 3.12,好处是新,代价是部分闭源驱动和工具链的适配还没跟上,CUDA 的一些老版本在新系统上装起来会比较折腾。
关键原则是:导入的发行版版本跟导出的那个保持一致。tar 包里是完整的文件系统,跨版本导入理论上可行(因为整个根文件系统都被替换了),但如果宿主的 WSL 内核版本和发行版差异过大,可能会在启动时遇到内核模块或 systemd 兼容问题。我原本是 22.04,导入的也是 22.04,最省事。
3. 把发行版和数据搬过去
这一步是整个迁移的核心技术环节。理解了export和import在做什么,后面所有问题都能自己想明白。
3.1 export 和 import 到底做了什么
wsl --export做的事情很朴素:把发行版的 ext4 根文件系统按目录结构打包成一个 tar。它不包含任何虚拟化相关的元数据,不包含 Windows 侧的注册表项,不包含 WSL 的全局配置。所以一个 tar 包可以理解为“一张 Linux 根文件系统的照片”。
wsl --import做的是反过来的事:把 tar 解包到一个新位置,然后在这个位置上创建一个新的ext4.vhdx,注册到 WSL 系统里。新的发行版名字、安装位置都由你指定,这就是为什么导入是把 WSL 搬到新盘的最佳手段——因为安装位置这个参数完全可控。
完整命令:
# 导出(旧机器上执行,注意先 shutdown) wsl --shutdown wsl --export Ubuntu-22.04 D:\wsl-backup\ubuntu2204.tar # 导入(新机器上执行,要先把 WSL 组件装好) wsl --import Ubuntu-22.04 D:\WSL\Ubuntu-22.04 D:\wsl-backup\ubuntu2204.tar --version 2这里面有几个参数值得说明。第二个参数是安装目录,导入后会在这个目录下生成ext4.vhdx。第三个参数是 tar 文件路径,可以是本地路径也可以是网络路径,但强烈建议本地,因为解包过程是密集 IO,走网络会慢到无法接受。--version 2指定用 WSL2,如果你要恢复的是 WSL1 环境就改成 1,但 2024 年了,新环境没必要用 WSL1。
导入完成后有一个必须处理的问题:默认用户会变成 root。原因是 WSL 的默认用户信息存在 Windows 侧的注册表里,tar 里没有这部分。解决办法是在发行版内部写/etc/wsl.conf:
[user] default=你的用户名保存后回到 PowerShell 执行wsl --terminate Ubuntu-22.04,再重新进入就好了。如果你连用户名都不确定,先wsl -d Ubuntu-22.04进去,ls /home看一下就有答案。
提示:如果你的发行版是 22.04 及以上,还可以在
/etc/wsl.conf里加[boot]段的systemd=true,让 WSL 用 systemd 作为 init。这会显著改善服务管理、Docker、时区同步这些行为。代价是启动稍慢,以及某些依赖非 systemd 环境的脚本可能需要调整。
3.2 为什么要顺手把默认路径挪出 C 盘
WSL 默认把发行版装在%LOCALAPPDATA%下面,也就是 C 盘。这在笔记本上是个隐患:一个带 CUDA、Docker、几套 Conda 环境的发行版,轻松就是 100G 以上,加上 Docker Desktop 的镜像和容器数据,200G 也不稀奇。C 盘一旦满了,Windows 会开始各种异常,而且清理 C 盘时你根本不知道哪些能删。
我的做法是:一开始导入就指定到数据盘。上面那条--import命令里D:\WSL\Ubuntu-22.04就是有意指定的。目录结构我会这样组织:
D:\WSL\ Ubuntu-22.04\ ext4.vhdx Ubuntu-24.04\ ext4.vhdx D:\WSL-Backup\ ubuntu2204-20240601.tar备份和运行环境放同一个物理盘,这样迁移盘的时候一起走。但要注意别放在同一个分区里互相挤空间,导入一个 60G 的发行版解包后可能膨胀到 90G,再加上 tar 本身的 41G,你需要提前留出双份空间。
对于已经装好的发行版想要挪位置,只能走 export 再 import 的老路,过程中不能简单地复制文件。这个过程我实测下来,60G 的发行版在 NVMe 上导出加导入大约 12 分钟,主要时间花在 tar 的压缩解压上。
3.3 那些容易漏掉的环境细节
导入完成后,发行版能启动、能进 shell,不代表环境就恢复了。我列一份逐项检查清单,按重要性排序。
权限和所有者。tar 保留权限位,但如果你在打包时用了某些会丢失权限的方式(比如中间经过 Windows 文件系统再拷一次),导入后可能出现~/.ssh/id_rsa权限变成 777 导致 SSH 拒绝使用的情况。修法很直接:chmod 700 ~/.ssh && chmod 600 ~/.ssh/*。
符号链接。Windows 文件系统不支持 Linux 式的符号链接,所以千万不要把 tar 解包中转放在 NTFS 上再打包。一定直接用wsl --import一次到位。如果发现环境里有软链接指向奇怪的位置,检查一下是不是在迁移过程中被展平了。
crontab 和 systemd 服务。crontab -l看一下有没有残留任务;如果启用了 systemd,systemctl list-units --failed检查一下有没有服务启动失败。常见失败原因是服务依赖的监听端口被占用,或者配置文件里写死了旧机器的 IP。
时区与时间。WSL2 会从 Windows 同步时间,但虚拟机休眠久了容易出现时间漂移。一个直接的办法是sudo hwclock -s强制同步,或者在/etc/wsl.conf里加[time] useWindowsTimezone=true。
locale 和中文文件名。如果导入后出现乱码,检查locale输出,需要的话装locales包并sudo locale-gen zh_CN.UTF-8。这个在跨机器恢复时比较容易被忽略,尤其是从其他语言环境的机器上迁过来的。
包管理器的全局状态。pip 的全局包、npm 的全局包、conda 的 base 环境,这些都在文件系统里,导入后应该都在。但要注意 npm 全局包的 bin 目录是否还在PATH里,~/.bashrc和~/.profile里的 PATH 追加语句如果引用的是绝对路径,需要确认路径没变。
3.4 旧机器的收尾工作
新机器跑通之后,旧机器上的 WSL 发行版要记得注销,否则它占的空间会一直留在那里,而且如果两块盘同时在机器里,可能会出现两个同名发行版的混乱。
# 在旧系统上执行,这个操作会永久删除发行版和它的 vhdx wsl --unregister Ubuntu-22.04我必须强调:wsl --unregister是不可逆的,它不会问你要不要保留数据,直接删。执行之前务必确认导出文件已经在新机器上成功导入并且环境验证通过。我的做法是:新机器上至少正常使用两周,确认没有任何遗漏,再回头处理旧盘,而且在处理旧盘之前把 tar 包再复制一份到别的地方存着。
如果你不打算立刻格式化旧盘,可以直接做个裸盘备份放着。一块 500G 的固态按现在的价格也就两三百块,当移动硬盘用都比重新配置环境划算。
4. 开发环境与性能的恢复调优
环境能跑起来只是及格,真正提高生产力的是把这些细节调顺手。这一段讲的是我从旧环境完整恢复之后做的几个配置调整,踩过的坑都在里面。
4.1 软件源与下载速度
新导入的发行版默认用的是官方源,在某些网络环境下apt update会慢到让人怀疑人生。换源的思路很简单,把archive.ubuntu.com和security.ubuntu.com替换成国内镜像。
Ubuntu 24.04 开始用 deb822 格式,配置文件是/etc/apt/sources.list.d/ubuntu.sources,格式跟老的sources.list不一样,不能照抄老教程。22.04 及以前还是/etc/apt/sources.list。改之前先备份:
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak然后替换域名。常见选择有清华 TUNA、中科大 USTC、阿里云,我一般选一个延迟低的,用ping或者直接curl -o /dev/null -s -w '%{time_total}'测一下响应时间。改完之后sudo apt update,正常情况下几十秒内完成,如果还卡着不动,多半是 DNS 问题而不是源的问题。
pip 同理,在~/.pip/pip.conf或者~/.config/pip/pip.conf里配index-url。conda 在~/.condarc里配channels。这两个配置文件在 home 目录里,会跟着 tar 一起搬过来,所以通常不用重新配,但换机器后建议检查一下里面的 URL 是不是还有效。
4.2 Docker Desktop 的 WSL2 后端接入
Docker Desktop 的 WSL2 后端是我认为最值得用的一种模式,因为它把 Docker 引擎直接跑在 WSL2 里,性能比 Hyper-V 后端好,文件挂载也方便。
配置步骤:安装 Docker Desktop,打开设置 → General,勾选 “Use the WSL 2 based engine”;然后到 Resources → WSL Integration,把需要集成的发行版打开。这一步做完,你在 WSL2 里直接敲docker ps就能用宿主机的 Docker 引擎了,不需要在发行版里再装一套 Docker。
有一个地方要注意:Docker Desktop 的镜像和容器数据默认也是存在 C 盘的,具体在%LOCALAPPDATA%\Docker\wsl\下面。我的处理办法是在 Docker Desktop 的 Settings → Resources → Advanced 里把 Disk image location 改到数据盘,改动之后它会提示迁移,确认即可,迁移过程需要几分钟。
如果你不用 Docker Desktop,而是在 WSL2 里直接用 apt 装 docker-ce,那么在启用 systemd 的前提下,sudo systemctl enable --now docker就能搞定。这时候有一个隐藏的成本:Docker 的数据目录默认在/var/lib/docker,这个路径就在 WSL 的 vhdx 里面,镜像多了会把 vhdx 撑得很大。把它挂到 Windows 盘(/mnt/d)上虽然能省 vhdx 空间,但性能会掉得很厉害,因为跨文件系统的 IO 要经过 9p 协议转发,实测下来小文件随机写能慢十倍以上。我的建议是宁可让它在 vhdx 里,定期用docker system prune清理,也不要挂到 Windows 盘上。
4.3 GPU 和 CUDA 的恢复要点
如果你在 WSL2 里跑训练或者推理,这块最容易被恢复时的操作顺序搞崩。核心原则只有一条:Windows 侧装驱动,WSL 侧装工具链,WSL 里千万不要装显卡驱动。
具体来说,Windows 上要装 NVIDIA 的 WSL 专用驱动,装完之后在 Windows 的 PowerShell 里跑nvidia-smi应该能看到显卡。然后在 WSL 里也跑一次nvidia-smi,如果能输出同样的表格,说明 GPU 直通已经成功了,WSL 侧不需要任何额外配置。
接下来才是装 CUDA Toolkit 和 cuDNN。这里有个版本对应关系必须搞清楚,装之前先看一眼 Windows 驱动支持的 CUDA 最高版本(nvidia-smi右上角会显示),然后去装不超过这个版本的 CUDA。举例来说,驱动显示支持到 CUDA 12.4,那你装 12.4 或者更低都行,装 12.5 就会报版本不匹配。
# 验证 GPU 直通 nvidia-smi # 装完 CUDA Toolkit 后验证 nvcc --version # PyTorch 侧验证 python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)"一个特别容易踩的坑:如果你的发行版是从别处导入的,CUDA 目录/usr/local/cuda下的文件都在,环境变量也在,看起来一切正常,但可能跟你新装的 Windows 驱动不匹配。判断方法是看nvcc --version和nvidia-smi报的 CUDA 版本是否兼容。如果不匹配,卸载重装 Toolkit 就行,不用动驱动。
4.4 用配置文件把资源分配调明白
.wslconfig放在C:\Users\你的用户名\下面,用来控制 WSL2 这台轻量虚拟机的资源。不配的话,内存默认是宿主的一半或者 8G(取较小值,不同版本策略略有差异),CPU 是全核,swap 是内存的 25%。对我来说默认值经常不合适,比如跑大模型推理时会 OOM。
我的配置大致长这样:
[wsl2] memory=24GB processors=12 swap=16GB localhostForwarding=true autoMemoryReclaim=gradual sparseVhd=true [experimental] networkingMode=mirrored dnsTunneling=true firewall=true autoProxy=true逐条解释一下我为什么这么设。内存给了 24G 是因为宿主机 64G,我要留足给 Windows 和其他程序。processors 给 12 是因为机器是 16 核,留几核给宿主避免卡顿。swap 给到 16G,因为训练脚本偶尔会有内存尖峰,有 swap 兜底不会直接杀进程。autoMemoryReclaim是让 WSL 定期把不用的内存还给 Windows,避免它一直占着不放。sparseVhd让 vhdx 支持稀疏,删掉大文件后空间能还给 Windows。
镜像网络模式networkingMode=mirrored需要 Windows 11 22H2 以上,作用是让 WSL 的网络跟宿主机共享,好处是外部设备能直接访问 WSL 里的服务,不需要做端口转发,代价是与某些依赖 NAT 的工具可能有兼容问题。
改完.wslconfig必须wsl --shutdown让所有实例退出,下次启动才生效,这一点很多人会忽略。
5. 常见问题与排查速查
迁移过程中遇到的问题,绝大多数都可以归到几类里。我做了一张速查表,方便快速定位。
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 无法启动,提示未启用虚拟化 | BIOS 虚拟化未开,或相关 Windows 功能未启用 | 进 BIOS 打开 VT-x/SVM,再启用虚拟机平台功能 |
wsl --import报错找不到文件 | 路径含空格或非 ASCII 字符,或用了相对路径 | 用绝对路径,路径中的空格用引号包住 |
| 导入后登录是 root | WSL 默认用户信息不在 tar 里 | 写/etc/wsl.conf的[user] default=段 |
| 外部工具连不上 WSL 里的服务 | NAT 模式下 IP 每次重启会变 | 用端口转发,或改用镜像网络模式 |
| vhdx 删除文件后空间没释放 | vhdx 不会自动收缩 | 手动压缩,或开启 sparseVhd |
| 时间越来越不准 | 虚拟机长时间休眠导致时钟漂移 | sudo hwclock -s或配置时区同步 |
| GPU 不可用 | Windows 驱动非 WSL 版本,或 CUDA 版本超出驱动支持 | 换 WSL 专用驱动,重装匹配的 Toolkit |
| 环境自检类工具报错 | 工具从 Windows 侧读 WSL 信息失败,或内核版本过旧 | 执行wsl --update,检查工具的运行位置 |
5.2 网络访问与外部工具连接的细节
WSL2 默认是 NAT 网络模式,这意味着 WSL 有一个独立的内网 IP,宿主和外部设备访问它需要经过一层地址转换。这个 IP 每次重启 WSL 都会变,所以任何写死 IP 的配置都会在某天突然失效。
如果你需要从局域网里其他机器连接 WSL 里的 SSH 服务,有两个选择。一是用宿主机做端口转发,在 Windows 上用管理员权限的 PowerShell 执行:
netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=22 connectaddress=<WSL的IP>同时要在 Windows 防火墙里放行 2222 端口。这个方法的缺点是 WSL 的 IP 变了之后要重新配。
二是如果你的系统支持,用镜像网络模式,配置就在上一节的.wslconfig里。开完之后 WSL 和宿主机共享网络栈,局域网设备直接访问宿主机的端口就能到 WSL,省掉转发这一层。我用下来这个模式在 Windows 11 上很稳,唯一的注意事项是它和某些会修改网络栈的软件可能冲突,出现问题时先关掉它排查。
5.3 磁盘空间不释放的处理
这是一个高频问题:你在 WSL 里删了几十 G 的文件,df -h显示空间释放了,但 Windows 上看到的 vhdx 文件还是那么大。原因是 vhdx 按需扩展但不自动收缩。
新版本的 WSL 支持一条命令解决:
wsl --manage Ubuntu-22.04 --set-sparse true执行完之后 vhdx 会变成稀疏文件,未使用的空间会还给 Windows。如果这条命令报错说不支持,说明 WSL 版本较旧,先wsl --update。
老办法是用 diskpart 手动压缩,过程稍微麻烦一点但适用性更广:
diskpart select vdisk file="D:\WSL\Ubuntu-22.04\ext4.vhdx" attach vdisk readonly compact vdisk detach vdisk exit压缩前建议先在 WSL 里清理一下:sudo apt clean、docker system prune -a、清掉 conda 的 pkgs 缓存。这些清理能让压缩效果明显很多,我曾经靠这三步把一个 120G 的 vhdx 压到了 63G。
6. 几条我踩过坑才明白的经验
最后说几条具体的经验,都是从实际出问题之后总结的,不是文档里会写的。
其一,导出的 tar 包不要放在 C 盘。我第一反应是导到桌面方便找,结果 41G 的 tar 加导入时解包的 90G,直接把 C 盘撑爆,Windows 开始各种异常。导出的包和解包的目标目录都应该在数据盘上,且要预留至少两倍的空间。
其二,导入完成后先做一次最小验证,不要急着装东西。最小验证的顺序是:进 shell →whoami看用户 →ls ~看文件 →ping一下外网 →nvidia-smi(如果有 GPU)→docker ps(如果配了 Docker)。这五项全过,说明底子是好的,后面装什么都只是时间问题。如果一开始就急着恢复复杂环境,出问题时你分不清是导入的锅还是新装的东西的锅。
其三,把环境重建步骤写成一个脚本放进 dotfiles 仓库。这次迁移让我意识到,环境的可复现性比环境本身更值钱。我把所有的手动操作写成了一个setup.sh,包括换源、装基础工具、配 git、恢复 SSH 密钥权限、装 conda、配 Docker,下次换机器或者换发行版直接跑一遍。这个脚本不是一次写完的,而是这次迁移过程中边做边记,遇到一步就记一步。
其四,迁移完成之后保留旧盘至少两周。别急着格式化。这两周里你会陆续发现“啊手机号验证器忘了导出”“那个项目依赖的密钥文件在旧 home 目录里”这类问题,有旧盘在手,插上就能拿,没有的话就只能重来。
其五,注意发行版名称和实际操作的关系。迁移后我遇到过一个问题:导出的 tar 里 family name 还是ubuntu,但如果我想在同一个系统里同时装 22.04 和 24.04 两个版本,导入时要给不同的名字,比如Ubuntu-22.04和Ubuntu-24.04。名字有冲突时wsl --import会直接报错,提示已存在同名发行版。这时候要么改名字,要么先注销旧的。名字建议就用发行版加版本的格式,清晰不容易搞混,而且很多脚本和工具会读这个名字,太随意的命名后面会有麻烦。
这套流程走完,我从一台换了新盘的机器上完整恢复了开发环境,包括那个带着 CUDA 的 Ubuntu 22.04,前后一共花了大概五个小时,其中两个小时在等文件拷贝和 tar 解包。相比于从零配置,这个时间成本是可接受的,而且过程中我对 WSL2 的哪些东西是“文件”、哪些是“元数据”、哪些是“外部配置”有了更清楚的认识。以后再遇到类似的迁移场景,我会更倾向于一开始就用导入到数据盘的方式装 WSL,而不是装完再想办法搬,因为那才是这个工具最舒服的用法。