排障–奥日2加载一下就闪退(已解决附补丁)
前情提要
前一阵子Steam上面奥日2打折,就买了一个,但是都玩不了。
具体故障很是神奇,打开游戏就在奥日奔跑的页面,有时候奔跑会剧烈掉帧,最后就出来个unity崩溃弹窗,整个游戏自动关闭。但是这一套不能稳定复现,有时候甚至能进去游戏,但是就算进去了也没有声音。


老子游戏呢???
网上解决方法
首先肯定是查一下网上的类似问题的解决方法拉,我找到了这些:
1.切换时区。准确点说,是把系统里面呗吞掉的时区改成北京时间,就行。 记录一次解决奥日2无限加载问题的经历-百度贴吧
2.切换版本。Steam提供了老一点的版本的下载,直接切换就行。(也就是那个开发者补丁,或者叫做patch2版本)开发者补丁解决ori2开始游戏黑屏问题-百度贴吧
3.更新显卡驱动。A卡驱动,懂得都懂🤣
4.启用Steam输入,来避免手柄导致的闪退。 https://www.bilibili.com/video/BV1SvB5YfEDh
5.更新vc++ …我这么懂电脑不至于卡在这个,基本忽略了。 解决奥日2无限加载和加载完黑屏-百度贴吧
6.文件夹直接启动。 【精灵与萤火意志】为什么我每次登录游戏都会闪退? – 知乎
7.调整声卡的输出格式,关闭空间音频,改配置文件把音频设备设为默认,api设为默认。 steam的奥日精灵与萤火意志为什么没有声音? – 知乎
8.锁定cpu核心来启动,只允许游戏调用1-2个大核心,进去游戏了再改。
9.使用dxvk转译后运行。—-甚至换了显卡,拿intel核显和P4单独运行。
但是,对我来说,都没用….. 特别是patch2版本,我给予了最大希望的,也是一样的报错,加载还慢不少。

先来放个环境吧。我当时最开始的时候是Win 10 22H2 版本是1904x.2xxx的版本。
硬件一直不变,是这个
| 项目 | 值 |
| CPU | Intel i9-13900HK(ES 工程样品),代号Q1HY |
| 内存 | 32 GB DDR5 6000 c38 美光颗粒 |
| 主显卡 | AMD Radeon RX 9070 XT,16 GB 显存(驱动 32.0.31041.1004) |
| 副显卡 | NVIDIA Tesla P4,8 GB 显存 |
| 操作系统 | Windows 10 专业工作站版(64 位) |
| 版本 | Build 19045(22H2),系统盘安装于 2026-06-18 |
其中这个CPU看起来是疑点重重,其实是啥毛病没有,当他是个13600k就行了,确认无bug。
那接下来,就是排障了
2026/6/15 –蓝色大肥鱼协助(失败)
6月–先是报错与分析
首先,报错肯定看log和系统日志。正好,unity游戏就有自己详细的报错。来看看吧
C:\Users\你的用户名\AppData\Local\Temp\Moon Studios\OriAndTheWilloftheWisps\CrashesCrash!!!
: Wwise: Cannot create streaming I/O device. :
UnityEngine.Logger:Log(LogType, Object, Object)
UnityEngine.Debug:LogError(Object, Object)
AkWwiseInitializationSettings:InitializeSoundEngine(AkWwiseInitializationSettings, WwiseBootstrapConfiguration)
Moon.Wwise.WwiseIntegration:Initialize(AkWwiseInitializationSettings, WwiseBootstrapConfiguration)
Moon.Wwise.WwiseBootstrap:Initialize()
Moon.Wwise.WwiseBootstrap:Awake()
UnityEngine.Object:Instantiate(T)
GameController:WarmUpResources()
GameController:Initialize()
StartupState:OnEnterState()
Bootstrap:Awake()
UnityEngine.Object:Instantiate(T)
Object:Instantiate(TObject)
GamePlaceholder:Awake()
emmm,看起来是wwise的streaming I/O device 炸了。这个一眼看是音频的Bug啊,直接从音频接口开始操刀(其实不是,被大肥鱼坑了,这个streaming似乎是从硬盘流式读取而非音频流式输出)
ds原话(呃呃坑死我了)
## 问题根因
Steam Streaming Speakers 虚拟扬声器干扰了 Wwise 2019.1.7 音频引擎的设备枚举。
- Wwise 遍历系统音频设备时,Steam 串流虚拟扬声器返回了无效参数
- 导致流式 I/O 设备创建失败
- Wwise 内部对象虚函数表损坏 ← 就是这里
- AK::StreamMgr::SetFileLocationResolver 调用时跳转到堆地址 → 访问违规
某个对象坏了 → 程序通过它做间接调用 → 跳到了不该跳的地方因为之前也碰到过音频不兼容导致的说法,先把steam虚拟扬声器禁用了看看。欸,居然进去了????稳定进去了几次,基本没有闪退,(虽然没声音)这也为这一次排障的路线偏离打下了伏笔。正好ds给出的结论是dll与内存布局的问题,说是win和老游戏的什么内存布局产生的冲突。于是,第一次折腾开始了
然后是尝试修复
当时锁定了这个方向,我做出了如下的努力。
1.在虚拟机里面装上同样版本的系统,发现故障依旧。更新到最新的win10版本之后,能玩了,一切正常。对比一下差异,音频相关的dll确实有一定的改变。还有一个变量就是amd显卡驱动
2.按照ds的推荐,关掉了amd的掉驱动检测服务和xbox gamebar,来尝试改变内存布局(A黑头子ds)
3.更新最新系统,和Primo Cache老版本驱动搏斗了2天终于装上了(微软也改了磁盘方面的驱动导致冲突)
4.禁用steam虚拟扬声器和amd音频输出,只留下一个螃蟹声卡
5.在虚拟机里面用ai的小脚本抓差异
6.臭骂amd并且更新显卡驱动
不过 ,可惜,还是没用…

2+3让我的闪退少了一点,但是仍然不能稳定进去游戏,也不能出声音
6月复盘
现在复盘一下,ds这里面的错误可不少。
① 那个函数名是猜的
AK::StreamMgr::SetFileLocationResolver(文件位置解析器)—— 听起来很专业,但没有调试符号时,工具只能拿"离得最近的导出符号名"去标记地址。九月算 RVA 再反汇编,发现那里根本是虚函数间接调用,不是什么文件位置解析器。② 不是”写入”,是”执行”
六月文本日志写的是 Write to location … caused an access violation(写入冲突)。九月看转储才发现 ExceptionInformation[0] = 8 = 执行违规。按照微软文档,**用户态数据执行保护(DEP)违规**——也就是”试图执行一段不允许执行的内存”
那么,这一点的改善是哪里来的?也许是内存布局变了带来的神奇小优化吧..禁用服务、关掉 Game Bar,改变的是谁往进程里塞 DLL、堆内存怎么复用 —— 说白了就是改变了撞车的概率。也正因为这样,这类操作永远只能”减轻”,不可能”治好”。概率降下来了,故障本身一动没动。
还好Steam客服给力,给我退款了。不过游戏文件我没删,要是哪天有救了呢?这可不是我玩盗版啊,是电脑不允许
2026/9/17 GPT6 Astra神仙救世
9月分析–抓真凶:错误码 87
最强llm出来了,手上有个pro20x和一堆reset,不猛猛蹬岂不浪费?正巧想到了这个bug,就让他们一较高下。
既然模型性能上来了,那要抓肯定要抓根本原因。就直接,来写一个补丁+详细冲突分析吧。
先是抓到了这么个东西:
Wwise: Cannot create streaming I/O device.
WwiseUnity: Failed to initialize the sound engine. Abort.GPT的世界知识还是暴打ds,一眼看出这可不是什么音频输出的bug,这是音频组件读取音频文件的问题啊!
原始报告写的出错的是这个:
AK::StreamMgr::SetFileLocationResolver但是,工具他只能拿到邻近的导出符号名去猜地址,并不知道详细信息。于是gpt开始了他的反编译:
AkSoundEngine.dll + 0x5B0C8
AkSoundEngine.dll + 0x5B16E
这是紧跟在虚函数间接调用之后,而崩溃时线程想跳转的目标地址,根本不在正常模块的代码区里。
除此之外,还有个冲突:Unity 的文本报告写的是”写入冲突(Write to location)”,但是ExceptionInformation[0]的值是8,表示用户态数据执行保护(DEP)违规。对不上啊。
接下来就是抓真正失败的调用了。
线程优先级: 0
线程核心掩码: 0xFFFFFFFC
线程栈大小: 128 KiB
SetThreadPriority 返回 1 → 成功
SetThreadAffinityMask 返回 0 → 失败
Windows 错误码 87 → ERROR_INVALID_PARAMETER
随后发生 0xC0000005 → 访问冲突有了错误码,自然就有了假设,游戏请求的掩码是 `0xFFFFFFFC`,而机器进程报告可用的只有 `0xFFFFF`,是不是请求了不允许的高位?但是随后的尝试又把这个假设给否定了。
把掩码从 `0xFFFFFFFC` 截断到 `0xFFFFC`,仍然87报错。这么说,禁用核心还是有点用的,但是不多。
反汇编:失败之后发生了什么
那么接下来,只能上反汇编了!GPT虽然逆向甲很厚,但是在这种拯救可怜穷鬼玩家的时候可不会藏着掖着,直接开整。
接下来就是GPT show time了,直接黏贴吧😂我也搞不懂啊
既然定位不到"为什么失败",就换个问题问:**失败之后,程序做了什么?**
反汇编这段逻辑之后,看到了一个要命的顺序:
```cpp
thread = CreateThread(/* 创建后立即可运行 */);
if (!ConfigurePriorityAndAffinity(thread)) { // 这里失败了(错误 87)
CloseHandle(thread);
thread = nullptr; // 句柄被清空
return InitializationFailed;
}
// ……后续清理阶段
if (thread != nullptr) { // 句柄是空的,于是跳过等待
WaitForSingleObject(thread, INFINITE);
}
// 然后,销毁线程还在用的那些对象
```
关键点在于:**关闭线程句柄 ≠ 结束线程。**
句柄可以理解成"访问系统对象的一张票"。把票撕了,线程还在跑。微软的 `CloseHandle` 文档写得很清楚:关闭线程句柄**不会**终止对应线程。
于是整个链条闭合了:
```mermaid
sequenceDiagram
participant M as 初始化线程
participant W as 音频读取线程
M->>W: CreateThread,立即可运行
M->>M: SetThreadPriority 成功
M->>M: SetThreadAffinityMask 失败(错误 87)
M->>M: CloseHandle 并清空句柄
Note over M,W: 关掉句柄不会让线程停下来
M->>M: 初始化失败,进入清理流程
Note over M,W: 句柄没了,后面的等待被跳过
W->>W: 通过已经失效的对象做间接调用
W->>W: 目标地址不可执行 → 0xC0000005
```
**这也顺带解释了那个"偶尔进得去但没声音"的诡异现象**:线程调度和内存复用有时间差。初始化失败时,声音引擎处于未就绪状态→没声音;而那个还在跑的线程会不会马上撞上失效地址,要看时机——撞上就闪退,没撞上就放你进去,但依然是静音的。
一个机制,两种表现。到这一步,之前所有零散的现象第一次被同一套解释串起来了。
8 字节补丁
既然BUG已经找到,那肯定要写补丁的了。既然触发点是”音频线程显式绑定核心失败”,那修复思路就很自然:别让它显式绑定。有意思的是,这个 DLL 自己就有这个分支——它的线程创建逻辑里,掩码为 0 时会直接跳过 `SetThreadAffinityMask` 调用,走正常的系统调度。
// 原来的导出函数(简化)
if (properties != nullptr)
properties->dwAffinityMask = suppliedMask;
// 补丁后
if (properties != nullptr)
properties->dwAffinityMask = 0; // 0 = 不显式绑定
具体改动:
```text
函数 RVA: 0x121F0
文件偏移: 0x115F0
原始:48 85 C9 74 03 89 51 04 C3 CC CC CC CC CC CC CC
补丁:48 85 C9 74 07 C7 41 04 00 00 00 00 C3 CC CC CC
```
怎么才算真修好?
然后就是GPT雷霆大验证了
这一步很重要,因为前面吃过"改完能进就算好了"的亏。所以这次定了**更严的通过标准**:
| 验证项 | 结果 |
| --- | --- |
| 原始 DLL 动态跟踪 | 绑定失败(错误 87),随后崩溃——**复现了故障** |
| 只缩小掩码 | 仍然失败——**否掉了错误假设** |
| 进程内取消显式绑定 | 通过音频初始化,进入后续场景 |
| 写入补丁后**普通启动**(无调试器、无运行时钩子) | 通过 |
| Windows 音频会话检查 | 活动、未静音、音量 100%,**检测到非零音频电平**(3 秒采样峰值 ≈ 0.01062) |
| 最后一次进程退出 | 我主动关的,不是闪退 |
| 安装 / 重复安装 / 还原 | 往返测试通过,还原后哈希与原件一致 |
两个细节值得单独说:
- **"普通启动"是关键。** 只在调试器下能跑通说明不了任何问题——普通启动也通过,才排除了"调试器掩盖了异常"。
- **"非零音频电平"比"看到游戏画面"强得多。** 检测只读取该游戏进程的音频会话状态和电平,不录音、不碰麦克风。它证明的是**游戏确实往 Windows 音频管线里送了声音信号**。
**但我也必须说清楚这个补丁没有解决什么:**
- 我**没有**搞清楚宿主机为什么拒绝这个游戏线程的绑定。这是绕过触发条件,不是根因修复。
- 没有完成长时间、全流程的游玩测试。
- 取消显式绑定可能改变性能特征(显式绑定时可能有它的性能目的)。
- 它**不是**"奥日 2 闪退通用补丁"。只对**特定 DLL 构建的特定故障路径**有效——安装器会校验完整 SHA-256,哈希对不上就拒绝执行。对比一下,GPT明显喜欢直接干软件原理,而ds更是被国内ai营销号那一套通用排障给驯化了一点?不过也不怪他就是,毕竟小模型。
事后总结
首先,Agent真是太好用了!不过也别全相信ai……
蓝色大肥鱼还是依旧吃白饭,不过看看账单 也没法发火。
技术上,首先这一套定位流程还是没问题的,控制变量有一些缺陷但也不是不行。
不过,还是有些可以改进的地方:
1. 过于轻信ds对于Wwise和streaming I/O device的描述,我该上网查的
2. 还是简单只看相关性而不是看因果。改变内存布局/禁用steam虚拟扬声器情况好一点了,于是宣布了修复,逻辑不够完备。在自身实力或者ai足够强的时候,还是需要一些打破沙锅问到底的精神,而不是祈求他机魂大悦次次能玩,留下悬案。
3. 相信转储这类,而不是文本。文本说”写入冲突”,转储说”执行违规”——两条线索指向完全不同的方向。二进制不会为了可读性美化自己。
4. 换显卡还是崩、更新驱动没解决、进去之后依然无声——这些反例一出现,就该把”显卡是主因”的优先级往下压,而不是继续找理由维持它。不要见到A卡就怪他。
5. 修奇奇怪怪Bug最好换大模型,见多识广真不一样
那么最后,也是附上了补丁,如果你和我碰到了同样的问题,那就自取吧
