wslc ps 卡死的排查:一次「停容器不停 VM」引发的连环故障
背景
前两天在 WSL 里跑着几个容器,用完正常把它们全停了。结果再执行 wslc ps -a 就彻底卡住了:
$ wslc ps -a
(光标闪烁,无输出、无报错、无超时)
不报错也不返回,就那么挂着。这种故障最烦人,因为你连错误信息都没有。
环境
| 项目 | 值 |
|---|---|
| Windows | 11 26H2,build 26300.9711 |
| WSL / wslc | 3.0.3.0 |
| WSL 内核 | 6.18.54.1-1 |
先搞清楚 wslc 到底是个啥
排查的第一步不是动手,是搞明白你面对的是什么。
wslc 并不是 wsl.exe 的一个子命令。它是 WSL 3.x 的容器 CLI,一个独立的可执行文件:
C:\Program Files\WSL\wslc.exe
InternalName: wslc.exe
FileDescription: Windows Subsystem for Linux Container CLI
FileVersion: 3.0.3.0
同目录还有个 wslcsession.exe(Description:Windows Subsystem for Linux Containers User Session),它是会话管理器,以 -Embedding 方式挂在 svchost 下的 COM 服务。
每个 Session 有独立的虚拟磁盘,放在 %LOCALAPPDATA%\wslc\sessions\<会话名>\ 下面,我这里是 54.4GB 的 storage.vhdx。
排查过程
第一步:找到「能返回」和「不能返回」的分界线
这是整个排查里最有价值的一步。把能跑的命令都跑一遍,结果非常整齐:
| 命令 | 结果 | 是否需要进会话 |
|---|---|---|
wslc version | 秒回 | 否 |
wslc --help | 秒回 | 否 |
wslc info | 秒回 | 否 |
wslc system session list | 秒回 | 否 |
wslc ps -a | 无限卡住 | 是 |
wslc images | 无限卡住 | 是 |
分界线清清楚楚:不依赖 Session 的命令全部正常,凡是要进 Session 干活的,全部挂死。
于是怀疑范围一下就缩小到了「会话层」,而不是网络、不是安装损坏、不是内核。
为了再确认一下不是网络问题,我把卡住的进程抓下来看了它的连接:
=== 该进程的网络连接 ===
(无 TCP/UDP 连接)
零连接。它是卡在本地 IPC 上等一个永远不会来的响应,跟网络、跟 HTTP 代理一点关系没有。
第二步:僵尸会话
既然怀疑会话层,就看会话:
$ wslc system session list
ID 创建者 PID 显示名称
1 82928 wslc-cli-DarkAthena
有个 Session 1,创建者 PID 是 82928。拿这个 PID 去查:
PS> Get-Process -Id 82928
>>> 不存在!会话创建者进程已消失 —— 僵尸会话确认
破案了。Session 的宿主进程早就没了,但会话管理器 wslcsession.exe 的账本里还把它列为活动会话。 所有命令进去执行,就在那儿干等着一个死人回话,自然永远不会返回。
这也解释了第一步的分界线:wslc info 只是问会话管理器要个清单,管理器自己能答;wslc ps 是要 Session 干活的,Session 是死的,自然挂死。
第三步:还有一把锁
按说把僵尸会话清掉就该好了。执行官方命令试试:
$ wslc system session terminate
(卡住,30s 无响应)
有意思,terminate 自己也卡住了——它同样得先进会话,典型的死锁。干掉它,直接送 wslcsession.exe 上路(COM 服务,杀掉会自动重新激活一个干净的):
PS> Stop-Process -Id 85468 -Force
再看会话表,干净了:
$ wslc system session list
ID 创建者 PID 显示名称
(空)
兴冲冲跑 wslc ps -a,这次不卡了,4 秒返回,但是甩出来一个新错误:
$ wslc ps -a
另一个程序正在使用此文件,进程无法访问。
错误代码: ERROR_SHARING_VIOLATION
第二层故障浮出水面:54.4GB 的 storage.vhdx 被别的进程独占锁着,新 Session 根本挂不上盘。
谁干的?看进程:
wslcsession.exe 22388
vmcompute.exe 16184
vmwp.exe 69116 创建于 2026/10/28 15:02:44,父进程 vmcompute
关键在这儿——我本机 4 个发行版全都是 Stopped:
NAME STATE VERSION
* Ubuntu-24.04 Stopped 2
rancher-desktop Stopped 2
rancher-desktop-data Stopped 2
Ubuntu-26.04 Stopped 2
发行版全停了,却有个 vmwp(虚拟机工作进程)还活着。再看时间戳,严丝合缝:
| 证据 | 时间 |
|---|---|
vmwp PID 69116 创建(父进程 vmcompute) | 10/28 15:02:44 |
会话 swap.vhdx 写入 | 10/28 15:02:46 |
vmwp 69116 就是那个僵尸 Session 的虚拟机,它从 10/28 起一直攥着磁盘不松手。
权限的天花板
剩下的事就是把这个 vmwp 弄走。于是有了这张很说明问题的表:
| 手段 | 结果 | 原因 |
|---|---|---|
taskkill /F /PID 69116 | 拒绝访问 | vmwp 是 PPL 受保护进程,管理员也杀不掉 |
Get-VM / Stop-VM | 不可用 | 本机没装 Hyper-V 管理工具,vmms 服务也不存在 |
Stop-Service vmcompute -Force | 卡在「正在停止」,停不下来 | 服务要停时得等 VM worker 清理,而那个 worker 卡着,两边互等 |
wsl --shutdown | 1 秒返回,无效 | wslc 的 Session VM 不在 wslservice 账本里,wsl -l -v 压根看不见它 |
杀 wslcsession.exe | 成功 | 用户态 COM 服务,可重建 |
这张表里最有意思的是 wsl --shutdown 那一行。wslc 的会话虚拟机压根不在 wslservice 的管理范围内,所以 wsl -l -v 永远列不出来它,常规的 WSL 排障手段一个都够不着它。这也是这类故障难查的根源——所有熟悉的命令都告诉你「一切正常」。
最后 Stop-Service vmcompute 卡在「正在停止」出不来,没辙,重启机器,一了百了。重启后 wslc ps -a 恢复正常,50GB 盘里的镜像和容器都还在,数据无损。
复盘:那 1.5GB 内存到底该不该管
回到开头。故障当天下午我是这么操作的:正常停掉所有 wslc 容器之后,发现任务管理器里 vmmemwslc-cli-DarkAthena 进程还占着不少内存,过了几个小时还有 1.5GB。于是尝试在任务管理器里结束它,报错,没结束成功,就先没管了。
先回答一个问题:这个 kill 操作是不是故障的直接原因?
按最简单的逻辑分析,它是一个「失败的操作」,理论上没改变任何状态。而且 vmmem* 这类进程本身也是受保护的,任务管理器结束不掉很正常。所以我倾向于认为它不是直接凶手。
但它绝不是无关操作,因为它暴露的东西才是真正的根因。
要点有三个:
1. 停容器不等于停 VM。
vmmemwslc-cli-DarkAthena 这个进程,本质上是 Windows 给这个虚拟化工作负载做的「内存记账」载体,它在任务管理器里代表 Session VM 占了多少内存。停掉容器只是让 VM 里没进程跑了,VM 本身还活着,内存自然不释放。
也就是说,「停了容器还占 1.5GB」不是内存泄漏,是** VM 压根没关**。而我盯着的那个 storage.vhdx 锁,正是这同一台没关的 VM 持有的。
2. 宿主进程退出了,VM 却留下了。
会话创建者 PID 82928 在故障发生前就已经不存在了。这是个拉胯的地方:宿主进程退出时没有把 VM 一并收走,VM 成了孤儿,而会话管理器账本里那条记录也没有被清理。两边一脱节,僵尸会话就这么诞生了。
至于 82928 究竟是什么时候死的、死在什么环节,进程已消失无从追溯,这部分我只能猜想。
3. 别去 kill vmmem。
既杀不掉(受保护),即使能杀掉也没用——它只是个记账的表象,真正的实体是 vmwp 托管的虚拟机。想释放,得从虚拟机这一层动手。
那正确的释放姿势是什么?
# 停容器之后,要释放资源得显式终止会话
wslc system session terminate
注意,实测本机 wsl --shutdown 对这个 Session VM 是无效的(前面那张表),别指望它。
总结
一句话:这次故障的根子是 wslc 停容器不停 VM,宿主进程退出后 VM 与会话记录两边脱节,产出「僵尸会话 + 磁盘锁」的连环套,最终让所有进会话的命令永久挂起。
几条实用建议:
- 排查判定:
wslc info秒回而wslc ps卡死,基本可以锁定是会话层故障,别往网络、代理、重装上浪费时间。 - 判定僵尸:
wslc system session list拿到创建者 PID,看它是否还活着,非常好使。 - 释放资源:用完容器想回收内存,走
wslc system session terminate,别手动去 killvmmem*,杀不掉也没用。 - 兜底手段:万一走到
vmwp持锁这一步,vmcompute停不下来就直接重启。记得先把wslcsession.exe清掉,让它重建干净的会话表。
最后说句实在的,wslc 这个东西在 wsl -l -v 里完全隐身,wsl --shutdown 又管不着它,出了问题所有熟悉的命令都说「一切正常」。这算不上 bug,但对排查的人来说确实不太友好。恐怕后面 WSL 得把这层账本也纳进统一管理,不然同类的问题还会再来一遍。
本文仅代表个人排查过程,环境为 Windows 11 26H2 + WSL/wslc 3.0.3.0,不同版本表现可能有差异。

