多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

WSL2资源分配实战:.wslconfig配置详解与内存优化

WSL2资源分配实战:.wslconfig配置详解与内存优化 装完 WSL2 之后你是不是也遇到过这种情况打开任务管理器一看Vmmem 这个进程把我 16G 内存吃掉了 8 个 GWindows 本体反而开始卡顿鼠标都飘了。或者反过来你在 WSL 里跑编译、跑模型训练内存动不动就 OOMLinux 直接给你把进程杀了而你 Windows 这边明明还闲着 10 个 G 的内存没用上。这就是 WSL 资源分配最让人头疼的地方。默认配置下 WSL2 会“自觉”拿走一半物理内存CPU 核心全部可调度而你想改它又不知道该动哪里。这篇文章不聊虚的直接讲透怎么重新分配 WSL 资源从 .wslconfig 里每一项参数的原理到具体该填多少值的经验公式再到改完之后的验证方法、踩坑实录一篇全给到位。适合刚接触 WSL 的人也适合已经在重度使用 WSL 但被资源问题困扰的老手。1. 为什么一定要重新分配 WSL 资源1.1 先搞清楚 WSL2 的默认资源占用逻辑WSL2 和第一代 WSL 最大的区别就是它跑在一个轻量级虚拟机里。WSL1 通过系统调用翻译层模拟 Linux 环境而 WSL2 是货真价实的 Linux 内核跑在 Hyper-V 虚拟化平台上。既然是虚拟机那 Windows 宿主机要给这个虚拟机分配 CPU、内存、交换空间这套分配规则直接决定了你的实际体验。默认规则是怎样的WSL2 会自动把宿主机物理内存的 50% 作为上限比如 16G 内存的机器WSL2 最多会占 8G。听起来还行对吧但实际遇到的问题是Linux 内核本身有很强的页面缓存机制。你在 WSL 里编译过几次大工程之后这些文件缓存会一直占着内存不吐出来。结果就是 WSL 虽然只“需要” 2G 内存但页缓存和缓冲可能占了 5GWindows 这半边反而内存紧张开始频繁访问虚拟内存。我见过一个比较典型的场景16G 内存的笔记本Windows 上开着浏览器加一个 IDE 大概吃掉 6G剩下 10G 被 WSL2 全部申请走了。按理说 Windows 还有富余但因为 WSL2 占了 8G 上限Windows 这边可用的物理内存只剩 2G系统卡到不行。这就是 WSL2 默认策略“偏袒 Linux”带来的副作用。1.2 内存之外CPU 和磁盘空间同样需要管理很多人只知道 WSL 吃内存忽略了 CPU 和磁盘的分配问题。WSL2 默认情况下宿主机所有逻辑 CPU 核心都可以被虚拟机调用。这听起来不是问题但实际上如果你的 Windows 还在跑视频编码、虚拟机、大型编译任务CPU 调度器要在 WSL 虚拟机和 Windows 进程之间来回切换双方互相争抢资源整体吞吐量反而下降。磁盘方面WSL2 的整个文件系统存储在 Windows 目录里的一个虚拟磁盘中默认是 ext4 格式放在 vhdx 文件里。这个虚拟磁盘最大的坑是只能增长不会自动收缩。你在 WSL 里编译过一遍大型项目或者装过几个深度学习框架虚拟磁盘文件可能膨胀到几十个 G即使你把里面的文件删干净了vhdx 文件还是那么大白白占用 Windows 的磁盘空间。所以重新分配 WSL 资源这件事不单单是改个内存数字那么简单CPU 核数、交换分区、网络模式、磁盘回收机制都需要一起理顺。这样才能让宿主机和 WSL 之间达到一个真正舒服的平衡点。2. 核心配置文件 .wslconfig 逐项拆解2.1 文件在哪里创建什么时候生效WSL2 的资源配置完全由一个文件控制.wslconfig。这个文件的路径在 Windows 用户目录下完整路径是C:\Users\你的用户名\.wslconfig。注意不是放在某个 Linux 发行版分区里面。我见过有朋友在 WSL 的/root目录下创建.wslconfig那当然不生效因为这个文件是 Windows 侧的配置文件只有在 Windows 用户目录下才会被 WSL2 的虚拟机管理进程读取。文件本身是纯文本格式可以用记事本、VS Code 等任意编辑器创建。每次修改完这个文件之后需要在 PowerShell 里执行wsl --shutdown然后重新进入 WSL 才会生效。只关闭终端窗口是不行的必须让整个 WSL 虚拟机完全停止再重启。2.2 memory 参数给 WSL 定一个明确的内存天花板.wslconfig中[wsl2]小节下的memory参数直接控制 WSL2 虚拟机可以申请的最大内存。默认值是宿主机物理内存的 50%你可以把它改成任意值。这里我直接给一套根据实践经验总结的分配参考表物理内存WSL 建议分配Windows 建议保留适用场景8G3G ~ 4G4G ~ 5G日常开发、轻量编译16G8G8G常规开发、Docker 容器32G16G ~ 20G12G ~ 16G大型编译、模型训练64G32G ~ 40G24G ~ 32G重型数据分析、多容器服务具体公式很简单物理内存 - Windows 日常保留内存 - 余量缓冲 分给 WSL 的值。Windows 日常保留内存看你的使用习惯浏览器加 IDE 大概是 4G 到 6G如果你还要跑 Windows 虚拟机再多加 4G 到 8G。为什么会强调“余量缓冲”因为 Windows 本身也有缓存和后台更新进程如果物理内存完全分干净当 Windows 突然需要更多内存时系统会去压缩内存甚至换页到磁盘整体响应速度会明显下降。我个人的习惯是至少留出 2G 的空余宁肯 WSL 少分一点也不要两边都难受。2.3 processors 参数核心数不是越多越好processors参数控制 WSL2 虚拟机可以使用的逻辑 CPU 核心数。默认情况下是宿主机所有核心都开放给 WSL。很多人觉得“多分几个核心给 WSL 跑得快”但实际测试下来并不是这样。如果你在 Windows 上同时要开浏览器、IDE、通讯软件Windows 这边的进程也需要 CPU 调度资源。WSL 占用过多核心时Windows 进程和 WSL 进程会在 CPU 调度器层互相干扰整体流畅度反而下降。建议按照这个逻辑来分配物理线程数 - 2 ~ 4。比如 8 核 16 线程的 CPU给 WSL 分配 8 到 12 个逻辑处理器4 核 8 线程的 CPU给 WSL 分配 4 到 6 个。如果你是重度 WSL 用户Windows 侧只跑轻量任务那可以多分一点几乎把全部核心给 WSL留一两个处理 Windows 的系统中断就行。这里要额外说一个容易搞混的点processors填的是线程数而不是物理核心数。比如你的 CPU 是 6 核 12 线程processors6表示 WSL 可以使用 6 个逻辑处理器也就是 3 个物理核心加对应的超线程。需要先通过任务管理器或者systeminfo查看逻辑处理器总数再决定填多少。2.4 swap 与 swapFile给 WSL 一张免死金牌swap参数控制 WSL2 虚拟机的交换分区大小。当 WSL 内的物理内存不够时会把不常用的内存页挪到磁盘上的交换文件中避免 Linux 内核直接触发 OOMOut Of Memory杀进程。默认情况下 WSL2 的swap大小是物理内存的 25%交换文件存放在%UserProfile%\AppData\Local\Temp\swap.vhdx。这个默认值有两个问题第一25% 的比例偏保守。如果你给 WSL 分配了 8G 内存默认 swap 只有 2G一旦内存吃紧Linux 的 OOM Killer 会毫不犹豫地杀掉正在运行的编译进程或模型训练进程。第二默认交换文件放在系统盘如果你的 C 盘剩余空间本来就不多交换文件大了以后很容易把系统盘塞满。我建议把swap调到和 WSL 分配内存相同的值或者稍微大一点。比如分配 8G 内存就配置 8G 甚至 16G 的 swap。对于一些内存密集型的任务比如 PyTorch 训练时数据集加载、大型 C 项目编译swap 大一些能给进程更多缓冲时间不会因为短时间内存峰值直接被干掉。swapFile参数还可以把交换文件放到其他盘。比如你的系统盘是 C 盘但剩余空间紧张可以改成swapFileD:\\wslswap\\swap.vhdx注意 Windows 路径中的反斜杠需要写成双反斜杠。2.5 networkingMode 与 localhostForwarding网络分配同样重要网络层面的配置也属于 WSL 2 资源分配的一部分尤其是当你需要在 WSL 里跑服务然后从 Windows 浏览器或者局域网其他设备访问这个服务时。localhostForwardingtrue是默认值表示 WSL 内监听端口的服务可以通过localhost地址从 Windows 侧访问。比如你在 WSL 里启动了一个 Flask 或 Django 开发服务器监听 8000 端口Windows 浏览器直接访问localhost:8000就能打开不需要额外配置。这个功能默认开启一般不用动。networkingModemirrored是 Windows 11 22H2 以及后续版本支持的新特性它让 WSL2 中的网络接口与 Windows 侧共享也就是“镜像”模式。默认的 NAT 模式下WSL 的 IP 地址是一个私有虚拟网络地址局域网内的其他设备访问不到。开启 mirrored 之后WSL 和 Windows 处于同一个网络接口局域网内其他设备可以直接访问 WSL 中监听的端口。如果你只是在本机开发调试localhostForwarding已经够用但如果你的工作流需要其他设备访问 WSL 里的服务就需要开启networkingModemirrored。这里要注意mirrored 模式对 WSL 版本有要求先把 WSL 升级到最新版再配置。2.6 Docker Desktop 联动时的额外关注点如果你在 Windows 上安装了 Docker Desktop并且开启了基于 WSL2 的后端那么.wslconfig里的资源配置会直接影响到 Docker Desktop 创建的 docker-desktop 发行版。特别是当你在容器里跑多个服务、构建镜像、跑数据库时内存不够用的情况很容易在 Docker 场景被放大——容器本身启动要占用内存Docker 的构建缓存和日志也会持续增长。所以 Docker Desktop 用户设置memory时要比纯命令行使用 WSL 的场景多留出一些空间。经验上是把 Docker 预计需要的内存一并算进 WSL 的分配值里。比如你在 Windows 上日常使用约 8G物理内存 32G那么 WSL 至少分配 16G否则启动三四个容器加一个构建任务就很容易触顶。3. 实操从零开始重新分配 WSL 资源3.1 先摸清当前 WSL 的资源使用情况动手改配置之前先看一眼 WSL 当前的资源占用到底是多少做到心中有数。在 PowerShell 里运行wsl --shutdown之前可以先进入 WSL 内部执行下面几条命令free -h nproc df -h /free -h能看到 WSL 当前的内存总量、已用量和 swap 情况nproc显示 WSL 可用的 CPU 核心数df -h /显示根分区的磁盘占用。记住这三个数据改完配置之后可以对比验证是否生效。还要顺便确认一下 WSL 版本。在 PowerShell 中执行wsl --version如果输出的版本号比较旧比如 WSL 1.x 或者早期 2.0建议先执行wsl --update升级到最新版因为下面要用的autoMemoryReclaim、sparseVhd等高级参数需要较新版本才支持。实测wsl --update如果卡在“无法与服务器建立连接”多半是需要先设置代理或者防火墙拦截了下载地址把网络问题解决之后再更新。3.2 通过 wsl --shutdown 完全停止 WSL 虚拟机修改.wslconfig之后必须完全停止 WSL 虚拟机再重启配置才会重新加载。正确的停止方式是打开 PowerShell执行wsl --shutdown这条命令会终止所有正在运行的 WSL 发行版和 WSL2 虚拟机。注意在 WSL 里运行的应用也会一并停止所以执行之前先保存好正在编辑的文件。停止之后可以检查一下任务管理器里是否存在Vmmem或VmmemWSL进程。如果进程还在等待几秒或者手动结束相关进程确认内存已经完全释放。然后重新打开一个 WSL 终端窗口WSL 会以新的配置启动。3.3 编写一份完整的 .wslconfig 配置下面给出一份适合 16G 内存 8 核 16 线程 Windows 机器的完整配置示例可以直接参考修改[wsl2] memory8GB processors8 swap8GB swapFileD:\\wsl\\swap.vhdx localhostForwardingtrue networkingModemirrored [experimental] autoMemoryReclaimgradual sparseVhdtrue逐行解释一下memory8GB给 WSL2 分配 8G 内存Windows 保留 8G 用于日常操作。processors8给 WSL2 分配 8 个逻辑处理器。16 线程的 CPU 里留一半给 Windows。swap8GB交换分区分配 8G和内存一样大给大型任务留缓冲。swapFileD:\\wsl\\swap.vhdx把交换文件放到 D 盘避免占用 C 盘空间。注意 D 盘目录需要提前创建好。networkingModemirrored开启网络镜像模式局域网设备可以直接访问 WSL 内服务。autoMemoryReclaimgradual这是 WSL 2.0 之后加入的实验性特性允许 WSL 在空闲时逐步释放缓存内存。实测开启后WSL 空闲时 Vmmem 占用会明显下降从动辄 6G 掉到 1G 以内。另一个可选值是dropcache它会在空闲时立即释放缓存但会牺牲一些下次访问文件的性能。日常使用推荐gradual。sparseVhdtrue启用稀疏虚拟磁盘vhdx 文件不会一开始就占满设定大小随着数据量实际增长。实测开启之后即使分配了 256G 的虚拟磁盘实际物理占用也只是几 G。如果你装的是 32G 内存 12 核 24 线程的机器可以用这个配置[wsl2] memory20GB processors16 swap16GB swapFileD:\\wsl\\swap.vhdx localhostForwardingtrue networkingModemirrored [experimental] autoMemoryReclaimgradual sparseVhdtrue记住一个原则WSL 分配的总资源不是越大越好而是要结合 Windows 侧的实际需求来动态平衡。3.4 重启 WSL 并验证配置是否生效配置好.wslconfig后进入 PowerShell 执行wsl --shutdown然后重新打开 WSL 终端运行以下命令验证free -h nproc cat /proc/meminfo | grep SwapTotalfree -h输出的Mem行里total应该显示为你配置的memory值nproc显示的数字应该等于配置的processors值SwapTotal应该等于配置的swap值。如果这几个数字和配置不一致回到第 4 节查看排查方法。如果一致说明配置已经生效。3.5 实测Vmmem 进程的内存占用稳定下降配置完成后我实际的感受是以前 WSL 空闲时任务管理器里的 Vmmem 进程稳坐 5~6G 不下来开启autoMemoryReclaimgradual并且调整 memory 上限之后空闲时 Vmmem 能降到 500M 以下。只有在实际编译、运行服务、加载模型的时候内存占用才会快速升上去任务结束之后又会缓慢释放回来。整个 Windows 侧的内存压力肉眼可见地改观了。这里额外分享一个小技巧。如果你发现在 Windows 侧localhost访问 WSL 服务偶尔不稳定同时你又开启了networkingModemirrored可以先试试把它改成 NAT 模式networkingModedefault。mirrored 模式虽然方便但在某些路由器环境下和 Windows 防火墙存在兼容性问题实测反复出现端口访问超时的情况改回默认 NAT 后问题消失。如果你的环境需要局域网访问再考虑镜像模式并确保 WSL 和 Windows 都更新到最新。4. 常见问题排查与避坑实录4.1 配置写了但没有生效改了.wslconfig之后进入 WSL 运行free -h看到的还是旧的内存配置这大概是遇到下面几种情况文件路径不对。.wslconfig必须放在C:\Users\你的用户名\.wslconfig不是 Windows 系统的任何其他目录更不是 Linux 分区内部。文件名写错。文件是.wslconfig注意没有前缀不是.wslconfig.txt。确认资源管理器里看不到.txt扩展名。修改后没有执行wsl --shutdown。单独一个个关闭终端窗口没用必须执行这个命令让整个虚拟机完全停止。参数写错。比如memory8G写成了memory8GB可以但8g小写可能不被识别。注意参数名大小写也有要求标准格式是memory8GB、processors8。如果你实在不确定哪一步出问题可以先用下面的方式确认 WSL 版本和当前加载的配置wsl --status wsl --version如果版本太旧先升级再试。4.2 执行 wsl --shutdown 之后 WSL 卡在启动界面这种情况多半是 WSL 虚拟机没有完全停止或者上一次运行时有残留进程阻塞了启动。打开任务管理器检查Vmmem或VmmemWSL进程是否还在。如果还在右键结束任务然后在 PowerShell 里重新执行wsl --shutdown再进入 WSL。如果还是卡住可以试着重置整个 WSL。在 PowerShell 里执行wsl --shutdown wsl --unregister 发行版名称注意unregister会删除这个发行版里的所有文件和数据操作前把重要数据备份出来。重新注册之后WSL 会以全新状态启动再重新设置一下默认用户通常就能恢复。4.3 Vmmem 的内存占用还是居高不下如果你已经设置了memory上限Vmmem 还是满负荷运行先分清楚是“虚拟机实际用到那么多”还是“缓存没释放”。进入 WSL 运行free -h看第二行buff/cache的值如果缓存值很高说明是 Linux 的页缓存占用了内存。这时候优先确认.wslconfig里是否开启了autoMemoryReclaimgradual同时考虑是不是 WSL 内部确实有长时间运行的服务比如 Docker Desktop 的后台进程、数据库服务、Node 服务等。如果确认没有常驻服务可以试试手动释放缓存。在 WSL 内以 root 权限执行sync sudo sh -c echo 1 /proc/sys/vm/drop_caches这会把页缓存强制刷掉内存会立刻降下来。不过这只是一种临时手段根本解法还是开启自动回收。4.4 遇到 “Too many open files” 错误在 WSL 里跑大型 Node 项目或者并发量比较高的服务时可能会遇到Too many open files错误。这个错误和 WSL 资源分配有一定关系但本质是 Linux 侧的文件描述符限制。可以先查看当前限制ulimit -n如果只有 1024说明默认限制太低。在~/.bashrc或~/.zshrc文件末尾加上ulimit -n 65535然后执行source ~/.bashrc生效。如果用的是 systemd 托管的服务还需要在 service 文件里设置LimitNOFILE65535。我的经验是跑了大型前端项目外加热更新时1024 的默认限制很快就会触顶改到 65535 基本能覆盖绝大多数场景。4.5 磁盘空间被 WSL 虚拟磁盘占满如何收缩 vhdxWSL2 的虚拟硬盘文件是“只增不减”的。你在 WSL 里删除了几十 G 的文件Windows 侧的 vhdx 文件体积不会有任何变化这个坑几乎每个 WSL 深度用户都踩过。收缩 vhdx 的完整步骤如下先在 PowerShell 中彻底停止 WSLwsl --shutdown打开 Windows 自带的磁盘管理工具 diskpart这里需要管理员权限。依次执行diskpart select vdisk fileC:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited...\LocalState\ext4.vhdx attach vdisk readonly compact vdisk detach vdisk exit注意 vhdx 的具体路径每个发行版不一样。可以在资源管理器里搜索ext4.vhdx找到实际路径。执行compact vdisk之后虚拟磁盘文件会压缩到实际使用的大小效果立竿见影。我实测过一个膨胀到 60G 的 vhdx 在清理文件后压缩到了 18G直接释放了 40 多 G 磁盘空间。5. 小结一下我个人的资源分配习惯做了这么多次 WSL 资源分配调整我自己的习惯是.wslconfig里永远不把 memory 给满而是给 Windows 留下足够余量同时开启autoMemoryReclaim和sparseVhd两个实验性特性前者解决内存缓存不释放后者让虚拟磁盘不再一上来就吃满空间。在具体数值上我通常按“Windows 保留一半WSL 用一半”的原则起步再根据实际任务慢慢微调。如果你发现 WSL 里跑编译用时太长就适当增加processors如果跑模型或者容器经常 OOM就增加memory或swap。每次改完都执行一遍wsl --shutdown然后进 WSL 用free -h、nproc验证。这个配置文件本身是比较稳定的不像系统其他配置那样频繁改动。调整到自己觉得舒服的状态之后基本就不用再动了。希望这篇文章能帮你把 WSL 的资源彻底理顺让 Windows 和 Linux 两边都跑得顺畅。
返回列表