欢迎光临
我们一直在努力

ChatGPT Windows 客户端点击无反应、有进程却没窗口?一次 MSIX 非系统盘启动卡死的完整排查

摘要:如果你的 ChatGPT Windows 客户端安装在 D 盘,更新后突然出现点击图标没反应、任务管理器里有进程、CPU 占用较高但始终没有窗口,可以尝试把应用移动到 C 盘。

本文不只提供解决方法,还会结合 Windows 事件日志、应用日志、残留文件和客户端代码,分析它为什么有效。

一、故障现象

这次问题出现在 Microsoft Store 版本的 ChatGPT Windows 客户端上。

故障表现包括:

  • 点击 ChatGPT 图标没有任何窗口;
  • 任务管理器中能看到多个 ChatGPT.exe 进程;
  • 主进程没有窗口句柄;
  • 某个 CPU 线程持续高占用;
  • 等待很久也没有进入登录界面或主界面;
  • 重启电脑、结束进程、卸载重装后仍可能复现;
  • 在 Windows 设置中把 ChatGPT 移动到 C 盘后,应用立即恢复。

如果你的现象与这些特征基本一致,本文的解决方法很可能适用。

不过需要强调:并不是所有ChatGPT 无法启动都由这个问题引起。如果应用原本就在 C 盘,或者日志中没有运行时暂存痕迹,还需要继续排查显卡、权限、配置文件或应用数据损坏等其他原因。

二、先说解决方法

推荐方法:把 ChatGPT 移动到 C 盘

打开 Windows 设置:

设置
→ 应用
→ 已安装的应用
→ ChatGPT
→ 移动
→ 选择 C 盘

不同 Windows 版本的入口可能略有差异,移动按钮也可能位于三点菜单或高级选项中。

移动完成后,重新打开 ChatGPT,然后就可以看到ChatGPT的页面了。

在本次故障中,同一个应用版本移动到 C 盘后,不需要清除数据或重新登录,窗口就恢复了。

备用方案:没有移动按钮时

可以先修改 Microsoft Store 新应用的默认安装位置:

设置
→ 系统
→ 存储
→ 高级存储设置
→ 新内容的保存位置
→ 新应用将保存到 C 盘

然后重新安装 ChatGPT。

卸载应用可能会清理一部分本地缓存和应用状态,因此操作前最好备份重要的本地内容。

不要手动移动 WindowsApps 文件夹,也不要随意修改它的所有者和访问权限。这可能破坏 Microsoft Store 的更新和完整性校验。

三、最初的判断:是不是文件在 C、注册在 D?

刚开始排查时,一个很容易出现的判断是:

应用注册在 D 盘,但更新后的文件被装到了 C:\\Program Files\\WindowsApps,因此形成了跨盘分裂状态。

后来通过 Windows 事件日志确认,这个结论并不正确。

AppX 部署日志显示,出现问题的两个版本都明确部署到了 D 盘:

OpenAI.Codex_26.825.4187.0
Target volume: D:

OpenAI.Codex_26.825.6671.0
Target volume: D:

Windows Error Reporting 记录的实际可执行文件路径也是:

D:\\WindowsApps\\OpenAI.Codex_26.825.6671.0_x64__…\\app\\ChatGPT.exe

因此,更新后的文件并没有偷偷跑到 C 盘。

之所以某些查询结果会显示:

C:\\Program Files\\WindowsApps\\OpenAI.Codex_…

是因为 Windows 会为非系统盘上的 AppX/MSIX 包建立逻辑入口或目录联接。表面路径可能位于 C 盘,物理文件实际上仍然位于 D 盘。

Microsoft 官方也说明,PackageVolume 不只可以位于 C 盘,也可以建立在其他驱动器上:Understanding how packaged desktop apps run on Windows。

所以,真正的问题并不是注册和文件分裂。

四、真正卡住的步骤:搬运 cua_node 运行时

ChatGPT 当前的 Windows 包中包含一个名为 cua_node 的运行时,里面包括:

  • node.exe;
  • node_repl.exe;
  • npm 相关文件;
  • Playwright;
  • OCR、图像和浏览器自动化相关依赖;
  • 大量 node_modules。

在本次版本中,这个目录大约包含:

文件数量:4680
总大小:318.88 MiB

应用启动时不会直接从受保护的 WindowsApps 目录使用这些文件,而是要把它们复制到用户目录:

%LOCALAPPDATA%\\OpenAI\\Codex\\runtimes\\cua_node\\

复制过程中会先建立类似下面的临时目录:

.staging-e4d75eceaa042f20-HCFkgX
.staging-e4d75eceaa042f20-naQjRk
.staging-e4d75eceaa042f20-8iFoyJ

全部复制完成后,暂存目录才会被重命名为正式运行时目录。

问题就发生在这个过程里。

五、本地留下了大量未完成的暂存目录

排查时,在本地发现了:

失败的 .staging-* 目录:21 个
残留文件:23832 个
占用空间:约 3.78 GiB

这些目录都没有最终的 manifest.json,说明运行时复制从未正常完成。

几个典型启动过程如下:

启动时间暂存目录最后写入进程结束已复制数据
10:22:20 10:36:13.775 10:36:14.094 257.05 MiB
10:46:30 10:58:45.949 10:58:46.225 262.65 MiB
11:02:09 11:13:37.231 11:13:37.895 239.06 MiB

暂存文件停止写入的时间与应用进程结束时间几乎完全一致。

这说明应用并非完全没有执行,而是一直在后台复制运行时。由于复制过程没有界面和进度提示,看起来就像点击图标毫无反应。

其中一次复制持续了约 15 分 40 秒,平均速度只有大约:

0.28 MiB/s

即使复制了十几分钟,仍然没有完成。

六、为什么 D 盘上的复制会这么慢?

进一步检查发现:

  • C、D 两个分区位于同一块 NVMe SSD;
  • 两个分区健康状态正常;
  • 因此不是 D 盘硬盘性能太差;
  • D 盘上的 AppX 物理包目录带有 Encrypted 属性;
  • 复制目标位于 C 盘普通的 %LOCALAPPDATA% 目录。

换句话说,应用是在把 D 盘加密的 AppX 包资源复制到 C 盘的普通用户目录。

更关键的是,客户端代码使用了同步文件操作。

其逻辑可以简化为:

// 同步读取并计算运行时文件哈希
hash = sha256(readFileSync(source))

// 同步递归遍历整个 cua_node
for (const file of files) {
copyFileSync(source, destination)
}

代码还专门处理了 Windows 错误码 6000:

try {
copyFileSync(source, destination)
} catch (error) {
if (error.errno === 6000) {
writeFileSync(destination, readFileSync(source))
}
}

Windows 错误码 6000 对应 ERROR_ENCRYPTION_FAILED,即加密文件复制失败。可以在 Microsoft System Error Codes 6000–8199 中查到。

当普通的 copyFileSync 无法直接处理加密资源时,应用会退化为:

  • 把整个文件同步读入内存;
  • 再同步写入目标目录;
  • 对数千个文件重复这个过程。
  • 而这一切发生在 Electron 主进程中。

    七、为什么会出现单线程高占用、始终没有窗口?

    Electron 的窗口创建、事件处理和一部分启动逻辑都依赖主线程。

    但 ChatGPT 在窗口创建前执行了大量同步操作:

    • 同步读取约 119 MiB 的关键文件并计算 SHA-256;
    • 同步遍历 4680 个文件;
    • 同步复制约 319 MiB 的运行时;
    • 遇到加密复制错误后,继续同步读写回退。

    只要这些操作没有结束,主线程就无法及时处理窗口创建和界面事件。

    最终表现就是:

    进程存在
    CPU 单线程高占用
    没有渲染进程或窗口
    应用日志不再继续输出

    失败启动的应用日志通常只留下三行:

    in_app_updates_policy_wait_started
    Launching app
    Appshot hotkey inactive

    这并不意味着更新检查或 Appshot 本身是根因。它们只是主线程进入同步运行时搬运之前,最后成功写入日志的步骤。

    Windows 最终也记录了正式的应用挂起事件:

    EventName: MoAppHang
    HangType: Quiesce
    AppName: ChatGPT.exe

    八、为什么移动到 C 盘后立即恢复?

    Windows 在设置中执行移动后,同一个应用版本从 D 盘迁移到了 C 盘。

    移动前:

    应用包:D:\\WindowsApps\\…
    运行时目标:C:\\Users\\…\\AppData\\Local\\OpenAI\\Codex\\…
    应用包属性:Encrypted

    移动后:

    应用包:C:\\Program Files\\WindowsApps\\…
    运行时目标:C:\\Users\\…\\AppData\\Local\\OpenAI\\Codex\\…
    应用包不再来自 D 盘加密 AppX 卷

    移动后的首次成功启动时间线为:

    12:07:44 启动同一个 26.825.6671.0 版本
    12:07:47 开始创建完整运行时目录
    12:07:56 318.88 MiB、4680 个文件复制完成
    12:08:06 主窗口完成加载并显示

    原来十几分钟都无法完成的复制,在 C 盘大约 9 秒就完成了。

    因此,移动到 C 盘有效的决定性原因不是修复了所谓的注册分裂,而是:

    它让 ChatGPT 不再从 D 盘加密的 AppX 包目录同步搬运运行时,极大降低了启动阶段的复制成本。

    九、这是 Windows 的问题,还是 ChatGPT 的问题?

    两边的设计共同触发了问题,但更直接的缺陷在应用侧。

    Windows 允许 Microsoft Store/MSIX 应用安装在非系统卷,这本身是受支持的能力。问题在于 ChatGPT:

    • 在窗口创建前搬运数百 MiB 运行时;
    • 使用同步递归复制;
    • 在主线程上同步计算大文件哈希;
    • 对加密复制失败逐文件执行同步回退;
    • 没有启动进度提示;
    • 没有合理超时;
    • 没有把耗时操作放到工作线程;
    • 进程被结束后留下大量未完成暂存目录。

    更合理的实现方式应该包括:

    • 将运行时物化放入后台线程或独立进程;
    • 先创建启动窗口并显示进度;
    • 使用异步流式复制;
    • 对 EFS 加密包使用专门的解密目标复制策略;
    • 为失败复制提供日志、超时和重试上限;
    • 下次启动时清理或复用有效的暂存数据。

    因此,这更像是 ChatGPT Windows 客户端在非系统 AppX 卷场景下的启动健壮性问题。

    十、如何判断自己是不是同一个问题?

    可以先检查 ChatGPT 包信息:

    $OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)

    Get-AppxPackage Name OpenAI.Codex |
    Select-Object Name, Version, InstallLocation, Status

    需要注意:InstallLocation 可能显示 C 盘逻辑入口,不能仅凭这一项判断物理文件在哪个盘。

    然后检查运行时目录:

    $runtimeRoot = Join-Path $env:LOCALAPPDATA "OpenAI/Codex/runtimes/cua_node"

    Get-ChildItem LiteralPath $runtimeRoot Force Directory |
    Select-Object Name, CreationTime, LastWriteTime

    如果存在大量这样的目录:

    .staging-xxxxxxxxxxxxxxxx-xxxxxx

    而没有对应的完整 16 位哈希目录,就很可能卡在运行时搬运阶段。

    应用日志通常位于:

    %LOCALAPPDATA%\\Packages\\OpenAI.Codex_2p2nqsd0c76g0\\
    LocalCache\\Local\\Codex\\Logs

    还可以检查最近的应用挂起事件:

    Get-WinEvent FilterHashtable @{
    LogName = "Application"
    Id = 1002
    StartTime = (Get-Date).AddDays(7)
    } | Where-Object {
    ($_.Properties.Value -join "|") -match "ChatGPT|OpenAI\\.Codex"
    } | Select-Object TimeCreated, Id, RecordId

    十一、总结

    如果你足够有耐心的话,可以不修改这个 bug,理论上,你只要等足够长的时间,它就会打开。因为我之前就有一次,当时看着其他文档时,它突然蹦了出来,当时以为是什么时候不小心点到了,可能实际上是它从 D 盘复制到 C 盘成功了。

    不过需要提醒:等待能否成功,取决于最新 staging 目录是否仍在持续增长。如果文件数、大小和修改时间长时间不再变化,或者不断产生新的 staging 目录,继续等待通常没有意义,建议直接按上文方法移动到 C 盘。

    十二、相关公开问题

    OpenAI 的公开问题列表中已经有高度相似的报告:

    • openai/codex#41093:安装在非系统 AppX 卷时没有 UI,移动到 C 盘恢复
    • openai/codex#41096:Windows 后台进程存在、CPU 高占用但无窗口

    这些公开问题证明并非个别机器才会出现该现象,但本文分析的同步运行时搬运和 EFS 回退机制,主要来自本机日志、残留文件与客户端包内代码的交叉验证,尚不能代表 OpenAI 官方已经确认相同根因。

    十三、为什么以前在 D 盘没事,更新后才出现?

    1. 正常启动不一定每次都复制 319 MiB

    cua_node 的正式缓存目录由运行时内容哈希标识。启动时如果已经存在与当前包匹配、带完整清单的缓存目录,客户端可以直接复用;只有缓存缺失、哈希变化或缓存不完整时,才需要创建新的 .staging-* 并重新搬运整套运行时。

    因此,同一个应用在 D 盘连续正常使用数月并不矛盾。旧版本很可能一直命中已经完成的缓存,没有在每次启动时重新复制数千个受保护文件。

    2. 这次更新改变了启动前提

    本机事件和文件时间线如下:

    时间发生的事情
    更新前 ChatGPT 一直安装在 D 盘,并能正常启动
    8 月 28 日 23:08 左右 26.825.4187.0 开始部署到 D 盘
    后续故障启动 新运行时哈希没有对应的完整缓存,客户端反复创建 .staging-*;共留下 21 个未完成目录
    9 月 1 日 11:48 26.825.6671.0 仍注册到 D 盘
    11:50、12:00 26.825.6671.0 在 D 盘启动,仍然只有进程、没有窗口
    12:04 Windows 将同一个 26.825.6671.0 成功移动到目标卷 C:
    12:07–12:08 同一版本重新启动,运行时约 9 秒准备完成,窗口随即出现

    最符合这些证据的过程是:

    旧版本日常启动
    → 已有完整的旧运行时缓存
    → 哈希匹配,直接复用
    → 正常创建窗口

    更新后首次启动
    → 当前包需要另一份运行时缓存
    → 没有匹配的完整目录
    → 从 D:\\WindowsApps 创建新的 staging
    → 受保护文件跨卷复制异常缓慢或无法完成
    → 主线程被占用,窗口无法创建

    同一版本移动到 C 盘后
    → 从 C 盘重新物化运行时
    → staging 正常完成并转为正式目录
    → 窗口恢复

    3. 为什么不能简单认为这次更新新引入了 bug?

    OpenAI 公开仓库中的 #34764 在更早的 26.715 版本就记录过高度一致的现象:非系统 AppX 卷、WindowsApps 文件受保护、复制返回错误 6000,以及移动到 C 盘后恢复。这说明底层薄弱点至少在更早版本已经存在。

    本机现在能够确认的是:

    • 故障确实紧跟 26.825.4187.0 更新出现;
    • 该版本的启动确实反复创建了新的运行时暂存目录;
    • D 盘包资源确实带有 Encrypted 属性;
    • 后续版本在 D 盘仍失败,而同一版本移动到 C 盘后成功。

    但旧包已经被 Store 替换,无法再对比旧版本的 cua_node 内容、哈希、复制实现和文件保护属性,也就无法把变化精确定位到某一个 OpenAI 代码提交或某一次 Windows Store 部署行为。

    所以更严谨的结论是:

    8 月 28 日的更新改变了运行时缓存条件,迫使客户端重新物化 cua_node,从而在这台机器上首次暴露了一个此前已经潜伏的非系统 AppX 卷 + 受保护文件 + 主进程同步复制缺陷;它是本次故障的触发点,不等于已经证明它是缺陷的最初来源。

    这也解释了为什么不是每次更新都会复发:如果某次更新继续使用同一个运行时哈希,完整缓存仍可复用;只有运行时内容变化、缓存失效或需要重建时,才更容易再次触发。

    因为我的电脑这个问题已经修复了,之前的旧包也已经覆盖了,没有办法对比了,如果有大佬知道是为什么,可以在评论区说一下。

    额外了解——为什么复制会这么慢?

    最核心的一点是:这并不是一次普通的 D 盘到 C 盘文件复制。对于受影响的文件,客户端会先尝试保留源文件加密属性的正常复制;这条路径失败后,再退化为同步解密、读取和写入。

    一个文件大致会经历下面的处理链:

    读取源文件并计算哈希

    copyFileSync 尝试正常复制

    Windows 尝试把源文件的 EFS 加密信息应用到目标文件

    目标文件加密失败,返回错误 6000

    readFileSync 通过 EFS 解密并读取源文件

    writeFileSync 把内容写入 C 盘普通目录

    处理下一个文件

    1. 正常复制路径会先失败一次

    D 盘 WindowsApps 中的源文件带有 Encrypted 属性。根据 Microsoft 的说明,Windows 复制 EFS 加密文件时,会先尝试使用源文件的加密密钥加密目标文件;如果不成功,再尝试使用默认密钥。两种方式都失败后,复制操作才返回 ERROR_ENCRYPTION_FAILED,也就是错误码 6000。

    参考:Microsoft:Handling Encrypted Files and Directories

    因此,每个受影响的文件都可能先经历:

    • 打开源文件;
    • 查询加密属性和密钥;
    • 调用 EFS 服务;
    • 创建或准备目标文件;
    • 尝试应用加密;
    • 最后失败并抛出错误。

    这次失败不一定已经复制了整个文件,但它会增加额外的文件系统、权限检查和加密服务开销。

    2. 失败后还要重新读取并写入

    从本地客户端包内代码观察到的简化逻辑如下:

    try {
    copyFileSync(source, destination)
    } catch (error) {
    if (error.errno === 6000) {
    writeFileSync(destination, readFileSync(source))
    }
    }

    发生错误 6000 后,客户端不再要求 Windows 保留原文件的加密状态,而是:

  • 再次打开 D 盘上的加密源文件;
  • 通过 EFS 解密路径读取文件内容;
  • 将完整内容放入内存;
  • 在 C 盘目标目录中创建普通文件;
  • 把内存中的内容同步写入目标文件。
  • 如果复制前还要计算 SHA-256,那么同一份数据还需要先被完整读取一次。一次处理可能包含:

    第一次读取:计算哈希
    第二次操作:尝试正常加密复制并失败
    第三次读取:解密并读入内存
    第四次操作:写入目标文件

    因此,实际工作量明显高于资源管理器中的普通复制。

    3. 大量小文件会放大固定开销

    cua_node 运行时并不是一个连续的大文件,而是由大量 JavaScript、JSON、原生模块和依赖文件组成。

    复制一个 1 GiB 的大文件,耗时通常主要取决于磁盘连续读写速度;复制数千个小文件时,大量时间则消耗在:

    • 打开和关闭文件;
    • 创建目录和文件;
    • 查询权限、属性和加密信息;
    • 分配与释放内存;
    • 更新 NTFS 元数据;
    • 对新生成的脚本、可执行文件和原生模块进行安全扫描。

    最后一项是否发生、耗时多少取决于本机安全软件配置,并非本次日志已经确认的主因;但它可能进一步放大小文件写入的成本。

    虽然 C、D 两个分区位于同一块 NVMe SSD,但它们仍是两个独立文件系统卷。跨卷操作需要真正读取源数据并写入目标卷,两个方向还会共享同一块 SSD 的控制器与闪存通道,不能因为位于同一块物理硬盘上就视为零成本操作。

    不过,约 319 MiB 的正常复制本身不应该长时间卡住。真正异常的是加密处理、逐文件同步操作和失败后的重复劳动叠加。

    4. 同步接口让复制串行化,也让窗口无法创建

    copyFileSync、readFileSync 和 writeFileSync 都是同步接口:

    Node.js:File system 文档

    同步接口并不会单独降低某一次内核复制的速度,但它有两个重要影响:

  • 当前文件没有处理完之前,程序不能开始处理下一个文件;
  • 如果这些操作运行在 Electron 主进程中,窗口创建和界面事件也必须等待。
  • 也就是说,应用不是在后台慢慢准备、同时先显示一个启动界面,而是把窗口创建也堵在了运行时准备流程后面。于是任务管理器里能看到进程和单线程高占用,桌面上却始终没有窗口。

    5. 3.78 GiB 是失败残留的累计值

    本机排查时发现:

    未完成的 .staging-* 目录:21 个
    残留文件:23,832 个
    占用空间:约 3.78 GiB

    这不代表一次启动需要复制 3.78 GiB。它是多次未完成操作留下的累计结果。

    每次启动都可能经历:

    创建新的 staging 目录

    复制一部分运行时文件

    复制失败、进程退出或被用户结束

    下次启动创建另一个 staging 目录

    再次执行前面的哈希和复制

    因此,用户感受到的“复制非常慢”,有时实际是“大量重复劳动,并且每次都没有到达完成状态”,而不是同一次复制一直在稳定前进。

    多个 staging 目录只能证明发生过多次未完成的准备过程,不能单凭它判断这些过程全部由应用自动重试产生;反复点击图标、手动结束进程或重启电脑,同样可能留下新的暂存目录。

    6. 为什么移动到 C 盘后很快恢复?

    移动到 C 盘会触发一次重新部署。根据本机移动后的检查,同一版本不再触发原先的 EFS 跨卷复制失败,运行时准备可以走正常路径:

    计算哈希

    正常复制

    staging 目录重命名为正式运行时目录

    创建应用窗口

    本机实测,移动后同一版本的运行时准备约 9 秒完成。因此,改善的关键并不是“C 盘物理速度一定比 D 盘快”,而是新的部署状态绕开了原先的加密复制失败和同步回退路径。

    7. 是否只要等待足够久就能打开?

    只有当所有文件最终都能成功处理,并且最新 staging 目录的文件数、大小和修改时间持续增长时,单次不受打断的启动才有可能在等待后完成。

    如果出现以下情况,继续等待通常没有意义:

    • 最新 staging 目录长时间不再变化;
    • 不断产生新的 staging 目录;
    • 始终无法生成最终 manifest.json;
    • 同一个加密、权限或校验错误反复出现。

    所以这次问题更准确的描述不是“D 盘太慢”,而是:

    D 盘 AppX 包的加密属性使正常复制路径失败,客户端随后采用同步、逐文件的解密读写方式兜底;大量小文件、哈希计算和多次未完成操作共同放大了启动时间,并阻塞了 Electron 窗口创建。

    赞(0)
    未经允许不得转载:171主机测评 » ChatGPT Windows 客户端点击无反应、有进程却没窗口?一次 MSIX 非系统盘启动卡死的完整排查
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址