前面那篇《Windows 11 下 5 分钟安装 Linux》介绍了怎么安装、以及怎么用起来。
装好之后用着用着,我们就会碰到一些奇怪的问题。比如明明 Linux 里删了一堆文件,Windows 磁盘空间怎么没变?再比如,从 WSL2 里访问 Windows 那边的文件,速度慢得出奇?还有,网络脚本昨天还好好的,今天 wsl --shutdown 一重启就连不上了?
这些其实都不是 Bug,而是 WSL2 底层设计直接带来的。搞清楚它的一些设计思路,这些问题就能很容易定位解决。
它到底是什么类型的虚拟机
我们知道,虚拟机有两种类型,一种Type 1(Bare Metal),直接在硬件上运行多种系统;另一种Type 2,则是在现有操作系统上运行虚拟机。
相比Type 2, Type 1运行效率更高,适合数据中心服务器;但是Type 2 更灵活,则适合开发测试人员运行的Workstation。
那Windows里的Linux算哪一种呢?
乍一看,Windows是在其里面运行Linux,不能单独运行Linux,而且一般我们也是在客户端使用,好像是Type 2。但是它的运行效率确实很高,几乎就像Bare Metal上运行一样。
实际的情况是,它既不是Type 1,也不是Type 2。或者说,它既有Type 1的效率,也有Type 2 的灵活性。
WSL2 在 Windows 内部运行着一个真正的 Linux 内核。
但这个"虚拟机"跟我们印象里的 VirtualBox、VMware 不一样。它叫 Utility VM(实用虚拟机),跑在微软自家的 Hyper-V Hypervisor 之上。
普通虚拟机要模拟一整套硬件:主板、BIOS、显卡驱动、存储控制器,开销很重。WSL2 的 Utility VM 把这些全跳过了:
- 不模拟 BIOS
- 不加载虚拟硬件驱动
- 不预留固定内存
它只向 Linux 内核暴露真正必要的东西:CPU 时间、内存页和 I/O 通道。结果是启动很快,而且闲置时内存占用近乎为零。
所以,如果非要给它分个类:Type 1.5——Hyper-V 打底,但比普通虚拟机轻得多。
这里要提醒一点:Hyper-V 其实分两层。一层是 Hypervisor 本体,Windows 11 启动时由系统引导程序直接加载,运行在操作系统"下面",属于 Type 1 级别——这一层一直在跑,WSL2 用的就是它。另一层是 Hyper-V 管理服务,也就是在 services.msc 里看到的那些"Hyper-V xxx"服务,那是给 Hyper-V Manager 和传统虚拟机管理用的。WSL2 根本不走那条路,所以那些服务关着也完全正常。
WSL1 到 WSL2 的进化历史
WSL2 为什么要这么设计?这个需要回头看看历史,我们要先看 WSL1 是怎么设计的,以及它的问题。
十年前(2016年8月)推出的WSL1 的设计思路叫系统调用翻译:当我们在里面跑 ls 或者 make,WSL1 会拦截这些 Linux 内核调用,实时翻译成对应的 Windows API。听起来挺聪明,但遇到真实场景就现原形了:
问题一:翻译本身就是开销。 每一次系统调用——读文件、创建进程、查权限——都要经过拦截、翻译、再执行这三步。这不是偶尔发生的,而是程序运行时每秒可能触发几千次的事情。累积下来,性能损耗极大。
问题二:文件系统根本就不兼容。 Linux 用的是 ext4,基于 inode 结构;Windows 用的是 NTFS,权限模型完全不同。WSL1 要在两套完全不同的文件系统之间实时做映射,Linux 的软链接、权限位、大小写敏感——这些在 Windows 里要么没有对应概念,要么行为不一样。翻译的代价极高,翻译的结果也不总是对的。
问题三:有些东西根本没法翻译。 这才是 WSL1 真正的死穴。容器(Docker)深度依赖 Linux 内核的 namespace 和 cgroups 机制——namespace 用来隔离进程视图,cgroups 用来限制资源占用。这两个是 Linux 内核的原生能力,Windows 上根本没有对应的东西,翻译无从下手。所以 WSL1 里,Docker 永远跑不起来。
WSL2 的解法非常直接:不翻译了,直接塞一个真正的 Linux 内核进去。
这样一来,Linux 程序发出的系统调用直接进内核,没有任何中间层。ext4 文件系统在 VM 内部原生运行,不需要跟 NTFS 做任何映射。namespace、cgroups 都是真实存在的,Docker 自然就能跑起来。
效率的提升不是"优化了一下",而是从根本上换掉了思路。
你的整个 Linux 就是一个文件
接下来,我们看看Linux在Windows文件系统究竟长什么样?
打开文件资源管理器,导航到 C:\Users\[用户名]\AppData\Local\wsl\,会看到一个用 GUID 命名的子文件夹(类似 {445ca81a-6e98-4e8d-aa7b-da5591a61d49} 这样一串)。进去之后,里面有一个 ext4.vhdx 文件。
(以前的旧版 WSL2 用发行版名称命名这个文件夹,比如 Ubuntu;新版改成 GUID 了。)

一个 Linux 系统在 Windows 里,就是这一个文件。我们安装的每个软件包、克隆的每个仓库、每一行写进去的日志——都在这里面。
这里,有一个反直觉的坑要提醒大家:.vhdx 是动态扩展的,数据越装越大,文件自然变大。但在 Linux 里删文件,.vhdx 不会自动缩小。
删了 20 GB 的依赖包?Windows 那边的磁盘占用纹丝不动。用了几个月,.vhdx 膨胀到几百 GB 是常见情况,即便 Linux 里实际存的东西远没那么多。
解决方案是 Windows 自带的 diskpart。先关掉所有 WSL 窗口,执行 wsl --shutdown,然后:
diskpart
> select vdisk file="C:\Users\[用户名]\AppData\Local\wsl\{你的GUID}\ext4.vhdx"
> attach vdisk readonly
> compact vdisk
> detach vdisk
> exit
这个操作会把虚拟硬盘里的"气泡"压缩掉,把空间还给 Windows。长期维护 WSL 环境的,应该把这步定期跑一次。
跨系统访问文件为什么这么慢
这是 WSL2 最常遇到的性能问题:在 Linux 里访问 Windows 那边的文件(比如 /mnt/c/ 下的内容),速度慢得离谱。重启 WSL、换个命令都没用。
那反过来呢?Windows 那边通过资源管理器打开 Linux 文件(就是左侧导航栏里的那个小企鹅图标),同样慢。
原因是一样的——两个方向走的是同一条通道。
WSL2 同时运行着两套完全独立的文件系统:
- ext4,在 Linux Utility VM 内部(路径形如
~/projects/) - NTFS,在 Windows 那边(从 Linux 访问时路径是
/mnt/c/)
不管哪个方向,只要跨越这条边界,请求都要经历:穿越 Hyper-V 虚拟化层 → 通过 9P 协议隧道传输 → 到达对方 → 数据再原路返回。每一次文件操作都走这一圈。
(9P 是一个网络文件共享协议。WSL2 内部运行着一个 9P 服务器,本质上是把对方的文件系统当成局域网共享来访问。)
任何需要频繁读写大量小文件的操作,每次都是一次 9P 往返,穿越虚拟化层——速度慢 10 到 50 倍是正常的。
结论很简单:文件放在哪里,就在哪里用。 在 WSL2 里工作的文件放在 Linux 文件系统(~/ 下);Windows 那边的项目就留在 NTFS 里。别让文件频繁跨边界,没有任何配置能绕过这个物理限制。
IP 总是在变
WSL2 启动的时候,Windows 会在内部搭一个"小型虚拟局域网":Linux 有自己的虚拟网卡,Windows 宿主机也有一张对应的虚拟网卡,两边通过这张虚拟网互相通信。这个虚拟网用的是 172.x.x.x 这类私有地址段。
麻烦的是,每次执行 wsl --shutdown 重启 WSL2,这个虚拟局域网就会重建一次,IP 地址重新分配。上次是 172.28.80.1,下次可能就变成 172.19.32.1 了。
这带来两个完全不同的问题,分开说:
从 Windows 连 Linux 服务:比如在 Linux 里跑了一个 Web 服务,想从 Windows 的浏览器打开——不用管 IP,直接用 localhost 就行。微软已经在 Windows 侧做了自动转发,这个方向不用操心。
从 Linux 连 Windows 服务:这个方向就麻烦了。比如脚本需要调用 Windows 那边的某个接口,或者连 Windows 本机的数据库——Linux 必须知道 Windows 宿主机当前的 IP 才能过去。
而这个 IP,正是那个每次重启都会变的地址。
好在 WSL2 每次启动时,会自动把 Windows 宿主机当前的虚拟 IP 写进 Linux 的一个配置文件里——/etc/resolv.conf:
cat /etc/resolv.conf
# nameserver 172.28.80.1 ← 这就是此刻 Windows 宿主机的 IP
所以,任何需要在 Linux 里回连 Windows 的脚本,都应该动态读取这个文件里的地址,而不是把某个 IP 写死在脚本里。写死了,下次重启就静默失效,不会有任何报错提示,只会让人一头雾水地排查半天。
防止 WSL2 把内存吃完
接下来,我们来说说 Linux 的资源占用如何配置。默认情况下,WSL2 可以吃掉最多 50% 的系统内存和全部 CPU 核心。在 32 GB 的机器上跑大项目时,这会明显挤压 Windows 侧的应用。
怎么配置呢?现在 Windows 已经自带了一个图形界面工具 WSL Settings,直接搜索打开,内存、CPU 核心数、swap 大小一目了然,改完点保存就行。

如果喜欢手动改,也可以直接编辑 C:\Users\[用户名]\ 下的 .wslconfig 文件:
[wsl2]
memory=8GB
processors=4
swap=2GB
两种方式效果一样。改完执行 wsl --shutdown 重启,即刻生效。这样就能把 Linux 占用资源设定一个限制,不会无限膨胀。
微软为什么要造这个东西
最后,有的朋友可能会好奇,微软为啥要专门费劲弄个 WSL2 呢?他们不怕 Linux 影响他们的生意吗?
其实,他们背后有几条很清晰的商业逻辑。
第一条:抢回开发者。 2010 到 2018 年间,大量开发者从 Windows 转向 MacBook,原因很简单——macOS 原生支持 Unix 工具链,Windows 开发者要跟 Cygwin、路径转义、权限不兼容死磕。微软意识到,得开发者者得生态。WSL2 是反击:让 Windows 变成开发者愿意用的平台。
第二条:云的线下前哨。 所有主流云平台底层都是 Linux。开发者在本地用 WSL2 练熟了 Ubuntu——学了 shell、apt、systemd——这些技能直接平移到云端。当他们需要上云时,阻力最小的路自然通向 Azure。
第三条:容器化时代的必要条件。 Docker、Kubernetes 需要真正的 Linux 内核。没有 WSL2,Windows 上的 Docker Desktop 就要用一个笨重得多的独立 VM。WSL2 让容器在 Windows 上变得好用,Docker 用得顺手,Azure 就离得近。
WSL2 不是一个产品,是一层战略基础设施。一家曾经把 Linux 称为"癌症"的公司,花了几年时间造出了世界上最流畅的 Linux 子系统——商业逻辑通了,一切就都说得通了。
防坑备忘
wsl --unregister 是物理级抹除! 执行之后,对应的 .vhdx 文件瞬间消失,没有确认提示,没有回收站,无法恢复。用之前务必先用 wsl --export [发行版名] [备份文件.tar] 做备份。
.vhdx 会悄悄膨胀。 Linux 里释放的磁盘空间不会自动归还给 Windows。长期用 WSL 的机器,定期跑一次 diskpart compact vdisk,不然某一天你会突然发现 C 盘满了。
文件放在哪影响性能。 在 WSL2 里,需要频繁操作的文件应该放在 Linux 文件系统(~/ 下),访问 /mnt/c/ 的速度会慢很多。跟用户说清楚这一点,能解决大部分"WSL2 怎么这么慢"的投诉。
内核报错先更新再重装。 WSL2 的 Linux 内核由微软独立维护,跟装的 Ubuntu 版本无关。遇到莫名奇妙的崩溃,先跑 wsl --update,别上来就重装——重装大概率解决不了内核层面的问题。
装好 WSL2 是第一步,搞清楚它的脾气才算真的会用。