2026-08-20技术quiet

UE5.8 着色器编译极慢,CPU 只有 20%?小心 Incredibuild / XGE 这个坑

GSWXY

GSWXY

Archivist & Author

UE5.8 着色器编译极慢,CPU 只有 20%?小心 Incredibuild / XGE 这个坑

最近在折腾 Unreal Engine 5.8 源码版时,遇到了一个相当折磨人的问题:

UE 编辑器启动非常慢,一直卡在“正在编译着色器”,但奇怪的是 CPU 并没有跑满。

一开始我还以为纯粹是电脑太老。

我的开发机配置大致是:

  • CPU:Intel Core i7-8700,6 核 12 线程
  • 内存:64GB
  • 显卡:RTX 2080
  • 系统:Windows
  • 引擎:Unreal Engine 5.8 源码版

i7-8700 确实已经是很多年前的 CPU,用现在的眼光来看,拿它编译 UE5 源码和 Shader 肯定不算快。

问题是,事情没这么简单。


一、最开始 CPU 明明能跑到 100%

第一次启动项目时,我打开任务管理器看了一眼:

CPU 直接 100%。

这看起来很正常。

UE 在第一次启动源码项目、生成 Derived Data Cache、处理 Shader、加载模块的时候,本来就会产生大量 CPU 工作。

于是我的第一反应是:

i7-8700 不行了,该换 CPU 了。

但过了一段时间以后,情况开始变得不对。

UE 依然停留在着色器处理阶段,可 CPU 却从 100% 掉到了大约:

20% 左右。

与此同时:

  • 内存只用了约 34%
  • 磁盘只有约 1%
  • GPU 也只有约 10%

也就是说:

CPU 不忙、内存没满、磁盘没满、GPU 也没满,但 UE 就是在那里慢慢磨。

这时候就不能简单用“CPU 老了”来解释了。


二、12 线程 CPU,只用了大约一两个线程

我的 i7-8700 是:

6 核 12 线程。

Windows 任务管理器显示整机 CPU 20% 左右,而 UnrealEditor 本身大约只有 12%。

粗略计算:

一个逻辑线程完全跑满,大约就是:

text
100% ÷ 12 ≈ 8.3%

也就是说,这个时候 UnrealEditor 实际上可能只有一两个线程在比较忙。

这就出现了一个很典型的现象:

界面显示还在处理 Shader,但整颗 CPU 根本没有充分参与工作。

换一颗更快的 CPU 当然可以提高单线程性能,但如果 UE 本身只让一两个线程干活,那么即便直接换 16 核、24 核,效果也不可能达到正常并行编译时的水平。

所以我决定先查 Shader 编译进程。


三、检查 ShaderCompileWorker,结果居然是 0

Unreal Engine 正常进行大量 Shader 编译时,会启动多个:

text
ShaderCompileWorker.exe

这些 Worker 才是 UE 用来并行处理 Shader 编译任务的重要组成部分。

我在 PowerShell 中执行:

powershell
Get-Process ShaderCompileWorker -ErrorAction SilentlyContinue |
Format-Table Id, CPU, WorkingSet, Path -AutoSize

然后统计数量:

powershell
(Get-Process ShaderCompileWorker -ErrorAction SilentlyContinue).Count

结果:

text
0

也就是说:

当时一个 ShaderCompileWorker 都没有运行。

这里需要说明一点:

看到 0 并不意味着 UE 一定坏了。

UE 新版本的一部分 Shader 预处理工作可以直接发生在 Editor 进程中,所以在某些阶段暂时没有 ShaderCompileWorker 是可能出现的。

但是,如果长时间显示 Shader 处理非常慢,同时 CPU 长时间只有十几个百分点,那么这个现象就值得继续查了。

Epic 在 UE 5.8 的控制台变量文档中也明确提供了:

text
r.ForceAllCoresForShaderCompiling

当它设置为 1 时,会忽略部分 INI 中关于保留线程的设置,尽可能启动与可用核心数量相匹配的 ShaderCompileWorker,以提高 Shader 吞吐量。需要注意的是,高核心数、低内存机器可能因此增加内存压力。

我的机器有 64GB 内存,因此这方面并不是主要问题。


四、先确认 ShaderCompileWorker 到底有没有编出来

因为我用的是 UE 5.8 源码版,所以另一个可能性是:

ShaderCompileWorker 根本没有正确编译。

于是继续检查:

powershell
Test-Path "D:\Unreal\UE5.8-Source\Engine\Binaries\Win64\ShaderCompileWorker.exe"

结果:

text
True

再检查整个目录:

powershell
Get-ChildItem "D:\Unreal\UE5.8-Source\Engine\Binaries\Win64\ShaderCompileWorker*" |
Format-Table Name,Length,LastWriteTime

可以看到:

text
ShaderCompileWorker.exe
ShaderCompileWorker.pdb
ShaderCompileWorker.modules
ShaderCompileWorker.target
ShaderCompileWorker.version

以及大量对应模块 DLL。

所以可以排除:

ShaderCompileWorker 没编译出来。

程序明明存在,但 UE 卡顿时 Worker 数量却是 0。

那就继续往下查。


五、真正引起注意的是:Incredibuild

在任务管理器里,我注意到了两个后台服务:

text
Incredibuild Endpoint Service
Coordinator Service

这就值得警惕了。

Incredibuild 本质上是一套分布式构建加速工具,而 Unreal Engine 本身支持通过 XGE 使用类似的分布式执行方式。

UE 5.8 官方的 BuildConfiguration 文档中,仍然存在:

text
bAllowXGE

其含义就是:

如果 XGE 可用,是否允许 UnrealBuildTool 使用 XGE。

默认值为 true

UE 5.8 还存在:

text
r.XGEController.Enabled

官方说明:

text
0 = 仅使用本地构建
1 = 使用 XGE 分发构建

默认值同样为 1

理论上,这东西本来是为了加速

但对于一台普通个人开发电脑,如果没有真正搭建好多台机器组成的 Incredibuild/XGE 分布式环境,或者 Incredibuild 的安装、授权、服务状态出现异常,就有可能产生一个非常反直觉的结果:

本来想加速,最后反而把本地并行编译拖慢了。


六、这并不是孤例

继续查资料以后发现,这个问题实际上很多年前就有人踩过。

Epic Developer Community 上曾有开发者遇到类似现象:

  • Shader 编译一段时间以后停止;
  • Incredibuild 参与 Shader 编译;
  • ShaderCompileWorker 数量异常;
  • CPU 无法充分利用;
  • 禁用或卸载 Incredibuild 后恢复本地并行编译。

有开发者反馈,移除 Incredibuild 后,原本只有少量 ShaderCompileWorker 工作的情况恢复为多个 Worker,同时 CPU 可以充分利用。

也有人遇到 UE 编辑器启动卡在 Shader 阶段,最后确认干扰来源就是 Incredibuild。

甚至到较新的 UE5 版本,Epic 社区中仍然可以找到 Incredibuild 与 ShaderCompileWorker/XGE 组合出现异常的案例。

所以这不是一个简单的:

“你的 CPU 太垃圾。”

而是应该先判断:

CPU 到底有没有被 UE 正确利用。


七、我的处理方案:单机开发直接关闭 XGE

我的使用场景很明确:

一台 Windows 开发机,本地编译 UE,没有 Incredibuild 分布式编译集群。

既然如此,与其让 UE 尝试调用 XGE/Incredibuild,不如干脆:

彻底使用本地 ShaderCompileWorker + UE 自己的本地编译能力。

我的处理原则是:

  1. 禁止 XGE Shader 分布式编译;
  2. Shader 编译尽量使用全部 CPU 核心;
  3. UnrealBuildTool 禁止使用 XGE;
  4. 保留 UE5 自己的 UBA 本地编译;
  5. 禁用 Incredibuild 后台服务。

八、永久关闭 XGE Shader

可以在工程的:

text
Config\DefaultEngine.ini

中加入:

ini
[SystemSettings]
r.XGEShaderCompile=0
r.ForceAllCoresForShaderCompiling=1

其中:

ini
r.XGEShaderCompile=0

目的是不再让 Shader 编译走 XGE 路径。

而:

ini
r.ForceAllCoresForShaderCompiling=1

则让 UE 在 Shader 编译时尽量使用全部 CPU 核心。

Epic 对 r.ForceAllCoresForShaderCompiling 的官方描述就是:设置为 1 后,忽略相关 INI 设置并尽可能按照可用核心数量启动 ShaderCompileWorker。


九、UnrealBuildTool 也禁掉 XGE

Shader 是一部分,C++ 编译又是另一部分。

UnrealBuildTool 在 Windows 下会读取:

text
%APPDATA%\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml

Epic 的 UE 5.8 官方文档确认,该目录属于 UBT 正式支持的全局配置位置。

可以配置:

xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
    <BuildConfiguration>
        <bAllowXGE>false</bAllowXGE>
        <bAllowUBAExecutor>true</bAllowUBAExecutor>
        <bAllowUBALocalExecutor>true</bAllowUBALocalExecutor>
        <bAllCores>true</bAllCores>
    </BuildConfiguration>
</Configuration>

几个参数的意思分别是:

bAllowXGE=false

禁止 UnrealBuildTool 使用 XGE。

Epic UE 5.8 文档中明确说明:

text
bAllowXGE

控制 XGE 在可用时是否允许被使用,默认值是 true

bAllowUBAExecutor=true

允许使用 Unreal Build Accelerator。

bAllowUBALocalExecutor=true

允许使用 UBA 的本地执行模式。

bAllCores=true

在计算可以使用多少 CPU 资源时,把逻辑核心也考虑进去。

换句话说:

不是关闭所有加速,而是不再使用不适合我当前单机环境的 XGE,把编译交回 UE 自己的本地执行体系。


十、Incredibuild 服务也可以直接禁用

如果自己本来就不使用 Incredibuild,那么仅仅修改 UE 配置以后,让它的 Endpoint、Coordinator 等后台服务继续常驻也没有什么意义。

可以在:

text
services.msc

中找到与:

text
Incredibuild
Xoreax

有关的服务,停止并设置为禁用。

如果完全用不到 Incredibuild,另外一个更彻底的办法就是:

直接通过 Visual Studio Installer 或 Windows 应用管理将其卸载。

对于单机 UE 开发而言,我个人更倾向于这种方式:

不使用,就不要让它参与构建链路。


十一、一个容易犯的错误:不要关闭 ShaderCompileWorker

排查这种问题时,网上还能搜到一些类似配置:

ini
r.Shaders.AllowCompilingThroughWorkers=0

这东西不要随便加。

我们的目标恰恰相反:

我要让 UE 正常启动多个 ShaderCompileWorker,而不是把 Worker 全关掉。

否则很可能让原本能够并行的 Shader 编译退化成更加低效的执行方式。

所以:

text
关闭 XGE ≠ 关闭 ShaderCompileWorker

正确方向应该是:

text
关闭异常的 XGE / Incredibuild 路径
        ↓
恢复 UE 本地 ShaderCompileWorker
        ↓
尽量充分使用 CPU 核心

十二、也不要动不动就删 DDC

还有一种网上很常见的“万能解决方案”:

删 DerivedDataCache。

这个操作确实可以解决某些缓存损坏问题。

但是:

如果 DDC 本身没有坏,就不要为了优化编译速度随便删。

因为删除以后意味着大量 Shader、纹理和其他 Derived Data 需要重新生成。

最终结果很可能是:

本来只是第一次慢,现在被自己手动变成再慢一次。

所以我的处理顺序是:

text
先看 CPU 利用率
↓
再看 ShaderCompileWorker 数量
↓
确认 ShaderCompileWorker.exe 是否存在
↓
检查 Incredibuild / XGE
↓
调整编译链路
↓
最后才考虑 DDC 是否异常

而不是上来就:

text
删 Intermediate
删 Saved
删 DDC
重新编译整个 UE

那样往往只会制造更多等待时间。


十三、怎么判断是不是同一个问题

如果你的 UE5 也出现以下组合,可以重点检查这一项。

症状 1

启动 UE:

text
Compiling Shaders...

长时间不结束。

症状 2

CPU 一开始可能达到:

text
80%~100%

后来却长期掉到:

text
10%~30%

症状 3

同时:

text
内存不满
SSD 不忙
GPU 不忙

症状 4

运行:

powershell
(Get-Process ShaderCompileWorker -ErrorAction SilentlyContinue).Count

发现大量 Shader 编译阶段:

text
0

或者只有极少数 Worker。

症状 5

任务管理器里又恰好存在:

text
Incredibuild Endpoint Service
Coordinator Service

那就非常值得检查:

是不是 XGE/Incredibuild 把 UE 的本地 Shader 编译链路接管了。


十四、别急着因为 Shader 慢就换电脑

这个坑给我最大的提醒其实不是 Incredibuild 本身,而是:

看到 UE 慢,不要立刻认为硬件性能不够。

我的 i7-8700 确实老了。

6 核 12 线程拿来开发 UE 5.8 源码项目,和现在的 16 核、24 核 CPU 相比,Shader 编译、C++ 编译、引擎源码编译肯定都会慢很多。

升级 CPU 依然是有价值的。

但:

text
CPU 100% 编译太慢

和:

text
CPU 只有 20%,UE 却在那里慢慢编

是两个完全不同的问题。

前一种可以通过升级硬件解决。

后一种首先应该解决的是:

为什么软件没有把现有硬件用起来。

如果一个 12 线程 CPU 实际只工作一两个线程,就算直接换一颗 32 线程 CPU,也只是把问题藏起来,而不是解决问题。


十五、总结

这次 UE5.8 Shader 编译问题的排查路径可以归纳成一句话:

UE 编译 Shader 很慢时,先别只看进度条,要打开任务管理器看看 CPU 到底有没有真正工作。

如果:

text
Shader 很慢
+ CPU 占用异常低
+ ShaderCompileWorker 很少甚至没有
+ 安装了 Incredibuild

那么 XGE/Incredibuild 就应该进入重点排查范围。

对于我这种:

单台 Windows PC + UE5 源码开发 + 不使用分布式编译集群

的环境,我更倾向于:

text
禁用 XGE
+
禁用 Incredibuild
+
使用本地 ShaderCompileWorker
+
使用 UBA Local
+
Shader 编译尽量使用全部 CPU 核心

简单、直接,也更符合个人开发机的实际情况。


最后

Unreal Engine 的很多“卡死”,其实并不是真的死了。

Shader、DDC、Cook、C++ 编译这些东西本身就很耗时间。

但正常的慢应该表现为:

电脑很忙,所以我在等它。

而不是:

电脑闲着,UE 却让我等它。

后一种情况,往往才是真正值得排查的坑。

这篇记录留在这里,希望以后再遇到类似问题时,不至于第一反应就是:

换 CPU。

Conversation

评论

0

首次发布需要审核,邮箱只用于必要联系。

正在加载评论…