昔日芳华Blog

INTP低精力人儿的小站

LR疯狂吃显存导致系统严重卡顿?—— 记为此尝试的历程与最终可行的“欺骗”

RESEARCH NOTE · WINDOWS / DXGI

24GB 显存的显卡被修图应用吃满、溢出、整机卡顿—— 最终的解不是”封顶”,而是只谎报一个数字,让应用自己收敛水位。

对象 Lightroom Classic 手段 DXGI 代理 结果 整卡占用 99% → 70% 副作用 零
TL;DR
  • Lightroom Classic 的显存分配是「水位线式贪婪」:它把 GPU 内存池填到接近「预算」才停手, 24GB 的卡也照吃不误,溢出到共享显存后拖慢整个系统。
  • 想直接「拒绝分配」来封顶?只会得到 纯红图片——它不处理显存分配失败。
  • 真正有效的做法:只谎报一个数字——DXGI QueryVideoMemoryInfo 返回的 Budget。 把它报小一号(本案例最终 10GB),Lightroom 自己就把水位稳住:整卡占用 ≈70%、零卡顿、零红图、零功能损失。
  • 实现是一个应用目录内的 dxgi.dll 代理(约两百多行核心逻辑),配置两行,重启应用生效,卸载 = 删文件。

01现象:24GB 显存,照样被吃满

一台 Win11 机器:64GB 内存 + 24GB 显存的 AMD 独显。症状:

  • Lightroom Classic 开着 GPU 加速修图一段时间后,显存被逐渐占满(整卡 90%+);
  • 随后开始溢出到共享显存(系统内存充当显存后备),整机明显卡顿;
  • 关掉 Lightroom 立刻恢复。换小显卡的机器反而没这么难受——

先做的第一件事是把测量做扎实。

02测量:厂商无关的「显存三只眼」

没有厂商工具也没关系,Windows 自带的性能计数器就是任务管理器的数据源:

PowerShellGet-Counter '\GPU Adapter Memory(*)\Dedicated Usage'    # 整卡专用显存
Get-Counter '\GPU Adapter Memory(*)\Shared Usage'       # 溢出到共享的部分
Get-Counter '\GPU Process Memory(*)\Dedicated Usage'    # 按进程(实例名含 PID)

两个坑先记下:

  • 别用 WMI 的 AdapterRAM:32 位截断,管你多大的卡都报 4095MB;
  • LUID 会变:按进程查显存时不要硬编码适配器 LUID,否则某次重启后采样会静默全 0。

测出来的核心事实:

显卡Lightroom 占用
4GB~90%
8GB~7 / 8GB
12GB~11.8 / 12GB
本机 24GB最高 25.6GB(溢出)
结论 跟卡多大无关——「给多少吃多少」是策略,不是需求。

03死路:硬上限与「全盘谎言」

尝试 A:硬上限(拒绝分配)

我们在应用目录放代理 DLL,拦截 D3D11/D3D12 的资源创建,超过天花板就返回 E_OUTOFMEMORY。显存确实被封顶了——但 Lightroom 画出纯红图片: 它根本没有写「分配失败」的处理分支。三次不同天花板,三次红图,结论闭环:

教训 它能容忍变慢(分页),不能容忍失败。

尝试 B:谎报一切数字

把专用显存、共享显存、DXGI 预算、显卡型号、物理内存挨个伪装了一遍:

  • 「系统信息」面板里数字都变了(说明谎报生效);
  • 分配行为纹丝不动。

当时得出的(后来被修正的)结论:Windows 用户态没有 per-process 显存上限 API, 唯一强制手段是「拒绝分配」,而这条路被应用堵死了。

04转折点:其实它有完整的显存管理

当真去读应用自己的日志和二进制之后,画风突变:

  • 引擎里有一个预算监视线程,监听系统的「显存预算变化」通知,并实时查询 QueryVideoMemoryInfo;
  • 运行日志里能看到它的池 / 缓存预算:基线约为报告预算的 86%(如 21.3GB / 24.9GB);
  • 日志里大量出现 TrimFootprint: x MB purged from pools ——它会主动清理内存池(单次最高近 17GB);
  • 它的 AI 子系统还有「内存受限 / 模型常驻」两档策略。
结论修正 它不是「没有管理」,而是「水位线定得太高 + 到点才清」—— 而这个水位线,是拿「你告诉它的预算」算出来的。

05解决思路:不砌墙,调水位

既然它的行为是 预算 → 水位 的自适应函数,那就只改这一个输入:

在 QueryVideoMemoryInfo 的应答里,把 Budget 从真实的 ~24GB 谎报为一个更小的值(本案例最终 10GB)。

一切照旧:分辨率、位深、功能全不变;只是它「以为的显卡」小了一号, 于是池预算、清理阈值全部等比例地更保守。

06实验数据与档位收敛

指标基线(真值)初版:三值都压到 8GB 最小集:只压 Budget=8GB回测:Budget=16GB(轻负载) 最终:Budget=10GB(重负载复测)
应用真实占用峰值25,642 MB13,902 MB12,613 MB15,025 MB 13,407 MB
整卡专用峰值24,315 MB(98.9%)15,305 MB12,374 MB 18,779 MB(≈77%)17,158 MB(≈70%)
分配拒绝 / 红图 / 报错—0 / 无0 / 无 0 / 无0 / 无 / 无
整卡专用显存峰值 · 对比(卡容量 24.5GB = 100%)
基线(真值)
99%
Budget=16GB 档
77%
Budget=10GB 档(最终)
70%
0 → 24.5GB 横轴仅为示意
边界教训 为什么从 16GB 收敛到 10GB—— 16GB 档在「轻负载」下表现完美(水位 ≈15GB、零清池);但当连续使用 AI 蒙版 (主体 / 天空 / 深度 / 皮肤)时,8 分钟内占用突发到 26GB、整卡 23.5GB(96%)、溢出 8.7GB。 预算机制管的是「池的常态水位 + 清理节奏」,管不住瞬时的大额突发 (AI 推理并行 + 模型常驻 + 推理缓冲,可以叠加数 GB)。 把档位下调到 10GB 后用同款重负载复测:专用峰值 13.4GB、整卡 ≈70%(余量 ≈7GB)、 AI 功能全部正常 → 定为最终档位。
误区澄清 关于「AI 蒙版时共享段涨到 4–7GB」:这是 ML 运行时把模型 / 工作缓冲放在系统内存的正常行为 (与预算档位无关、与 AI 工作量成正比),不是「显卡满到溢页」。 判定安全与否看两条:① 整卡专用是否接近满;② 是否有卡顿。 本案例重负载下整卡仅 70%,共享占用只是用掉 64GB 系统内存中的几个 GB。

数据口径:Windows 性能计数器(逐 8 秒采样)+ 应用自身日志;峰值为会话内最大值。

07原理复盘:为什么这一招成立

  • 应用本来就是「按预算自适应」的:同一套逻辑,在小显存卡上它会自动更保守 (这也是为什么 8GB 卡能正常工作的原因);
  • 预算越低估,它的池预算越小、清理越勤;预算越接近真实容量,就越接近「给多少吃多少」;
  • 全程没有任何分配被拒绝,所以永远踩不到它缺失的「OOM 错误处理」路径—— 这正是它比「硬上限」优雅的地方。

08教程:最小修改做法

8.1 原理

  • 应用目录中的 dxgi.dll 会被优先加载(dxgi 不是系统 KnownDLL);
  • 代理转发全部导出函数到系统真正的 dxgi,保持完全兼容;
  • 只做一处补丁:应用创建 DXGI 工厂拿到适配器对象后,把它虚表上的 QueryVideoMemoryInfo(槽位 14) 换成我们的版本;
  • 我们的版本先调用原函数,然后把应答里的 Budget(以及两个 Reservation 字段) 截断到配置值,其余原样返回;
  • 配置放 %TEMP%\lr_vram_cap.txt,进程启动时读一次。
应用水位算法
──QueryVideoMemoryInfo──▶
dxgi 代理返回 Budget=10240MB
──▶
应用收到应答其余逻辑 100% 原始
唯一被改动的字节:应答里的 3 个整数字段

8.2 步骤

  1. 获取 / 构建代理(仓库结构:dxgi_proxy.cpp + 转发桩 trampolines.asm + build.bat)。 工具链:VS 生成工具 + Windows SDK。构建后用 dumpbin /exports 对比系统 C:\Windows\System32\dxgi.dll 的导出表(本环境为 20 个),必须一一对齐, 少一个都会导致应用启动失败。
  2. 放入安装目录:<Lightroom 安装目录>\dxgi.dll。
  3. 写配置(%TEMP%\lr_vram_cap.txt):
    INI; 只谎报预算一个数字
    budget_mb = 10240   ; 谎报的显存预算(MB);0 = 关闭
    desc_mb   = 0       ; 谎报专用显存(0 = 真实值,本方案不需要)
    shared_mb = 0       ; 谎报共享显存(0 = 真实值)
    log       = 1       ; 写日志到 %TEMP%\dxgi_proxy.log
  4. 完全退出并重启 Lightroom(配置只在启动时读一次)。
  5. 验证:看 %TEMP%\dxgi_proxy.log,应出现 reportedBudget=10240MB 而 realBudget 仍是真实值。
  6. 回滚:删掉 dxgi.dll 与配置文件,重启应用即可。

8.3 数值怎么选

  • 从「真实显存的一半」起步(24GB → 12GB),确认有效后逐步上调;
  • 目标是:整卡峰值留 15~20% 余量、无溢出尖峰、操作无感知;
  • 本案例最终选 10GB(≈卡容量的 40%)——并用你日常最重的工作流做最后验证 (AI 蒙版类操作会带来数 GB 的瞬时突发,见第 6 节的边界教训);若后台还有重显存程序,再保守一档。

09适用边界与风险

  • 仅 Windows / WDDM;当前代码为 x64;QueryVideoMemoryInfo 需 Win10 1703+;
  • 只对「尊重预算」的应用有效——对完全无视该接口的软件等于没装;
  • 对游戏 / 引擎可能改变纹理流送策略(是「降质量」不是「崩溃」); 绝不要对带反作弊的在线程序使用;
  • Windows 更新后系统 dxgi.dll 的导出可能变化:升级后先跑一次导出比对脚本,必要时重新构建;
  • 杀软可能对「应用目录里的 dxgi.dll」敏感——请自行编译、来源可信;
  • 这不是官方方案:保留回滚手段,风险自担。

10常见问题

会不会让 Lightroom 变慢?
本案例 10GB 档在连续 AI 蒙版复测中无感知(各项推理耗时正常、无卡顿); 每一档都完全可用,差异只是它「守水位」的清理频率(低档位会非常勤快地清缓存)。
为什么不用 Windows 图形设置限制它?
没有这种设置——操作系统的图形偏好只管「用哪块 GPU」,没有 per-process 显存上限。
能用在 Photoshop 吗?
Photoshop 中的 Camera Raw 引擎与 Lightroom 同源(本案例观察到它也有同款 GPU 配置文件), 理论上同理,但未实测——请自行用日志验证。
怎么判断别的软件适不适用?
装上代理开日志,观察它是否调用 QueryVideoMemoryInfo、以及调用后行为是否变化; 不查询的应用装上也无效。

本文为个人实验记录,由AI辅助生成,请注意甄别。
与 Adobe 无关联,不构成官方支持复现风险自负修改第三方程序目录中的文件前请确保可回滚

发表回复

Your email address will not be published. Required fields are marked *.

*
*

Captcha Code

人,咪欢迎你来
咕咕猫儿
这是咕咕猫儿
咕咕猫出生于2024年7月8日 蓝双布偶弟弟

最新文章
最新评论

友情链接

内鬼酱~koishi
Giftia终端服务部
SSP97
卧槽.萌
1919810.com
氖罩测评网站
橙的核电站