一周写了 186 GB:WSLg 的 RdClientAutoTrace 撑满了 C 盘
原创 · 约 23 分钟阅读 · 阅读 --
最后更新于

一周写了 186 GB:WSLg 的 RdClientAutoTrace 撑满了 C 盘

作者: Alex Xiang


C 盘在一周里快速减少,排查时 952 GB 的磁盘只剩约 69.5 GB。最后找到的主因不是 Docker 镜像,也不是 110 GB 的分页文件,而是 WSLg 远程桌面组件留下的 12,729 个 ETL 文件。

这批日志占了 186.36 GB,而且仍以每天 17~41 GB 的速度增长。

WSLg 诊断日志持续写入 Windows C 盘

先建立空间基线

面对“C 盘突然满了”,第一反应往往是找最大文件。但最大文件不一定是最近的增长源。我先做只读检查:

Get-PSDrive -Name C |
    Select-Object Name,
        @{N='UsedGB'; E={[math]::Round($_.Used / 1GB, 2)}},
        @{N='FreeGB'; E={[math]::Round($_.Free / 1GB, 2)}}

Get-ChildItem C:\ -Force -File |
    Sort-Object Length -Descending |
    Select-Object -First 15 FullName,
        @{N='SizeGB'; E={[math]::Round($_.Length / 1GB, 2)}},
        LastWriteTime

根目录最显眼的两个文件是:

C:\pagefile.sys    110.47 GB
C:\hiberfil.sys     25.49 GB

它们很大,但都属于系统管理对象。尤其是 pagefile.sys,不能因为体积醒目就手工删除。

通过 WMI 查看分页文件后,能看到它采用系统管理大小,而且本次启动的峰值使用量很高。WSL 与终端进程也占据了较多内存提交量。这能解释分页文件为何扩张,却还不能解释一周内持续丢失的几百 GB 空间。

用目录聚合缩小范围

对整个 C 盘直接递归 Get-ChildItem,既慢又会打印海量结果。我用 robocopy /L 做只读枚举,只关心汇总数据:

robocopy "$env:LOCALAPPDATA" C:\Windows\Temp `
    /L /E /XJ /BYTES /NFL /NDL /NJH /R:0 /W:0

几个关键参数:

  • /L 只列出,不复制;
  • /XJ 排除目录联接,避免递归环和重复统计;
  • /BYTES 让结果按字节显示;
  • /R:0 /W:0 遇到不可访问项时不重试。

目录逐层拆分后,异常很快集中到 %LOCALAPPDATA%\Temp

Temp       209.2 GB
Docker     107.5 GB
Programs    16.5 GB
Microsoft   15.6 GB
uv           6.2 GB

继续按 Temp 的第一层目录聚合:

$root = "$env:LOCALAPPDATA\Temp"
$sizes = @{}

Get-ChildItem $root -Force -File -Recurse -ErrorAction SilentlyContinue |
    ForEach-Object {
        $relative = $_.FullName.Substring($root.Length).TrimStart('\')
        $top = ($relative -split '\\', 2)[0]
        if (-not $sizes.ContainsKey($top)) {
            $sizes[$top] = [double]0
        }
        $sizes[$top] += $_.Length
    }

$sizes.GetEnumerator() |
    Sort-Object Value -Descending |
    Select-Object -First 25 `
        @{N='Entry'; E={$_.Key}},
        @{N='SizeGB'; E={[math]::Round($_.Value / 1GB, 2)}}

结果不再含糊:

DiagOutputDir                         186.33 GB
<WSL 实例 GUID>\swap.vhdx              7.88 GB
Visual Studio 安装临时目录              5.40 GB

DiagOutputDir 里几乎全部是下面这个目录的 .etl 文件:

%LOCALAPPDATA%\Temp\DiagOutputDir\RdClientAutoTrace

按日期统计后,七天共生成 12,729 个文件:

日期文件数当日体积
7 月 12 日6798.87 GB
7 月 13 日1,41816.97 GB
7 月 14 日1,51321.27 GB
7 月 15 日2,53037.30 GB
7 月 16 日2,43034.84 GB
7 月 17 日2,48241.07 GB
7 月 18 日排查时1,54224.30 GB

到这里,问题不再是“什么占空间”,而是“谁在持续写这些文件”。

从 ETL 文件追到活动会话

.etl 是 Event Trace Log,属于 Windows ETW 事件跟踪输出。只删文件不停止会话,目录很快就会回来。

先看当前运行的跟踪会话:

logman query -ets |
    Select-String -Pattern 'RdClient|Remote|AutoTrace|Wpp'

现场结果里有:

RdClientAutoTrace    Trace    Running

再查询详情:

logman query RdClientAutoTrace -ets

其中几个字段很关键:

Root Path:          %LOCALAPPDATA%\Temp\DiagOutputDir\RdClientAutoTrace
Segment Max Size:   100 MB
Circular:           On
Buffer Flush Timer: 30 seconds
Provider:           TS Client ActiveX Control Trace
Provider:           TS Client Trace

它看起来配置了循环记录,但现场不断创建新分段,旧文件没有得到有效限制或回收。

确认写入者是 WSLg

接下来查看远程桌面相关进程的路径和命令行:

Get-CimInstance Win32_Process |
    Where-Object {$_.Name -match 'msrdc|rdclient|mstsc'} |
    Select-Object Name, ProcessId, ExecutablePath, CommandLine

现场进程来自:

C:\Program Files\WSL\msrdc.exe

命令行带有 /wslgWSLDVC_PACKAGEwslg.rdp 等参数。这说明它不是用户手动打开的普通远程桌面会话,而是 WSLg 图形转发链路的一部分。

WSLg 会让 Linux GUI 窗口自然出现在 Windows 桌面。Linux 一侧运行 Weston 等组件,Windows 一侧借助远程桌面技术完成画面、输入和音频集成。官方仓库里也有同类报告:WSL Issue #10216

先止血,再精确删除

第一步是停止写入会话:

logman stop RdClientAutoTrace -ets

然后再次查询,确认会话已经消失:

logman query -ets |
    Select-String -Pattern '^RdClientAutoTrace\s'

递归删除前,我没有直接对 %TEMP% 下手,而是解析绝对路径并限制允许范围:

$target  = "$env:LOCALAPPDATA\Temp\DiagOutputDir\RdClientAutoTrace"
$allowed = "$env:LOCALAPPDATA\Temp\DiagOutputDir"

$resolved = (Resolve-Path -LiteralPath $target -ErrorAction Stop).Path
$allowedResolved = (Resolve-Path -LiteralPath $allowed -ErrorAction Stop).Path

if (-not $resolved.StartsWith(
        $allowedResolved + '\',
        [System.StringComparison]::OrdinalIgnoreCase)) {
    throw "Safety check failed: $resolved"
}

再统计一次待删除对象:

$before = Get-ChildItem -LiteralPath $resolved -Force -File -Recurse |
    Measure-Object Length -Sum

[pscustomobject]@{
    Files  = $before.Count
    SizeGB = [math]::Round($before.Sum / 1GB, 2)
}

确认数量为 12,729、体积为 186.36 GB,且这些日志不再需要提交给技术支持后,才删除这个单一目录:

Remove-Item -LiteralPath $resolved -Recurse -Force

清理后,C 盘可用空间立刻从约 69.5 GB 增加到 255.8 GB。

只删日志为什么不够

第一次清理后,目录很快被重新创建,RdClientAutoTrace 又变成 Running。这证明它不是历史遗留文件,而是活动组件持续生成的输出。

定时删目录只能缓解容量问题,无法停止持续写盘,也会增加 SSD 的无效写入。修复必须改变创建会话的那条路径。

这类问题常见的处理方向有三种:

禁用 WSLg

.wslconfig 里设置:

[wsl2]
guiApplications=false

它最直接,但会失去 Linux GUI 应用,不适合仍要开发和调试 WSLg 程序的环境。

用同名文件阻止目录创建

社区里有人删除目录后,创建一个同名普通文件,让记录器无法再创建同名目录。这能止住文件增长,却可能带来新的跟踪启动失败事件,也没有解决底层路径。

切换 WSLg 的远程桌面路径

本次采用的是社区验证过的兼容方案,在 %USERPROFILE%\.wslgconfig 中加入:

[system-distro-env]
WSLG_USE_MSTSC=true

这个变量不是 Microsoft Learn 正式承诺的稳定配置接口,因此应该明确把它当成针对已知问题的临时兼容方案。WSL 更新后要重新验证;官方问题关闭并给出正式修复后,也应考虑移除它。

让配置真正生效

Docker Desktop 使用 WSL 2 后端,可能阻止系统虚拟机完全退出。我先正常停止 Docker Desktop,再关闭 WSL:

docker desktop stop
wsl --terminate Ubuntu
wsl --shutdown

随后重启 Docker Desktop 和 Ubuntu。这里不要为了“关干净”直接删除 Docker 的 VHDX,里面可能有镜像、容器层、卷和持久化数据。

验证不能只看目录暂时为空

修复后至少要确认五件事:

  • Ubuntu 能正常启动;
  • Docker Desktop 后端能运行;
  • RdClientAutoTrace 会话不存在;
  • 日志目录没有重新创建;
  • C 盘可用空间不再持续下降。

我用 5 秒间隔连续采样:

$tracePath = "$env:LOCALAPPDATA\Temp\DiagOutputDir\RdClientAutoTrace"

1..6 | ForEach-Object {
    Start-Sleep -Seconds 5

    [pscustomobject]@{
        Seconds = $_ * 5
        DockerBackend = [bool](
            Get-Process 'com.docker.backend' -ErrorAction SilentlyContinue
        )
        TraceRunning = [bool](
            logman query -ets 2>$null |
                Select-String -Pattern '^RdClientAutoTrace\s'
        )
        TraceFolder = Test-Path -LiteralPath $tracePath
        FreeGB = [math]::Round((Get-PSDrive C).Free / 1GB, 2)
    }
}

连续 30 秒里,Docker 后端保持运行,跟踪会话和日志目录都没有回来,可用空间稳定。

为什么最后又多释放了约 100 GB

日志清理后,可用空间从 69.5 GB 增到 255.8 GB;停止并重启 Docker Desktop 后,又增加到约 356.6 GB。

检查 Docker 数据盘:

Get-Item "$env:LOCALAPPDATA\Docker\wsl\disk\docker_data.vhdx" |
    Select-Object FullName,
        @{N='LogicalSizeGB'; E={[math]::Round($_.Length / 1GB, 2)}},
        LastWriteTime

现场看到它从约 107.4 GB 缩小到 14.4 GB。Docker Desktop 在正常停止和恢复期间回收或整理了稀疏 VHDX,额外释放约 93 GB。

这不意味着每次重启 Docker 都会得到相同结果,更不意味着可以直接删除 docker_data.vhdx。清理 Docker 资源应该先看:

docker system df
docker system prune

docker system prune 会删除未使用资源,执行前必须检查业务影响;涉及卷时尤其要谨慎。

最终结果如下:

指标处理前处理后
C 盘可用空间约 69.5 GB约 356.6 GB
RdClientAutoTrace12,729 个文件,186.36 GB会话停止,目录不存在
Docker VHDX约 107.4 GB约 14.4 GB
WSL 2 / Ubuntu运行中运行中
Docker Desktop运行中恢复正常
WSLg 图形功能可用保留
pagefile.sys110.5 GB未修改

留一个只读监控脚本

为了尽早发现复发,可以定期运行:

$tracePath = "$env:LOCALAPPDATA\Temp\DiagOutputDir\RdClientAutoTrace"

$traceBytes = if (Test-Path $tracePath) {
    (Get-ChildItem $tracePath -File -Recurse -ErrorAction SilentlyContinue |
        Measure-Object Length -Sum).Sum
} else {
    0
}

[pscustomobject]@{
    Time = Get-Date
    CFreeGB = [math]::Round((Get-PSDrive C).Free / 1GB, 2)
    TraceRunning = [bool](
        logman query -ets 2>$null |
            Select-String -Pattern '^RdClientAutoTrace\s'
    )
    TraceSizeGB = [math]::Round($traceBytes / 1GB, 2)
}

如果日志重现,再检查 .wslgconfig、WSL 和 msrdc.exe 的版本变化,以及 Issue #10216 是否已有正式修复。

结语

这次最危险的误判,是看到 pagefile.sys 和 Docker VHDX 很大,就准备先处理它们。真正的增长源藏在用户临时目录里,而且背后还有一个正在运行的 ETW 会话。

有效的处理顺序是:建立空间基线,逐层聚合目录,确认文件增长速度,追踪活动写入源,停止会话,校验路径后精确删除,最后重启相关组件并连续观察。

清理文件只能止血。让写入源停止,并证明它不会马上回来,才算修复。

打开原图 ↗