卡顿诊断复用记录
归档日期:2026-09-16。ver-25/26/27 是独立诊断分支,不作为长期正式库;正式 ver-28 经用户明确要求回到干净的 ver-24 底座并增加实时 FPS。历史成品、构建工具与测试证据保留,不覆盖、不重新编号。
三次诊断各解决什么
| 版本 | 用途与结果 | 产物目录(相对 G:/.exe/lua) |
| ver-25 | 主循环 12 阶段、队列和慢事件,每约 2 秒/最多 900 条;用户复现缩小到地图逻辑/主角属性链,尚不足以定罪具体函数 | analysis_output/Heimei-EG-lua_ver-25-performance-diag/ |
| ver-26 | 30 项固定函数探针,包含/自身耗时、次数和覆盖状态;修正截断前 dt、NPC 数量口径。2 秒/900 组,每组三行 | analysis_output/Heimei-EG-lua_ver-26-performance-detail/ |
| ver-27 | 保留 ver-26 计时,只改 10 秒/180 组;同时前端两处空道具守卫。后续日志定位时装整档导出和灵宠读取反复写保护表 | analysis_output/Heimei-EG-lua_ver-27-point-fix/ |
字段、30 项函数映射和安装方式仍以卡顿诊断版为准。所有可直接测试的历史库位于 DM3引擎/被魔改文件/,分别为 Game_Heimei-EG-lua_ver-25_卡顿诊断.lib、Game_Heimei-EG-lua_ver-26_精细诊断.lib、Game_Heimei-EG-lua_ver-27_低频诊断.lib,哈希以全局版本台账和各版 final.manifest.json 核验。
ver-26 进游戏异常:14:17:29 FATAL 指向空装备格被按脱装访问 nil。无诊断库的隔离源码也能复现,不能仅凭日志很多判定日志致死;同样不能由隔离复现排除诊断对触发时机的影响。ver-27 的两个空值守卫在前端 game/items/穿戴api.lua 和 装备_增减_玩法_规则.lua,不是 Game.lib 内修复,切回干净库也必须保留。
下次遇到类似卡顿
1. 先记录实际开发端/外端目录、横幅版本、部署库或内嵌程序哈希,以及落盘日志。别把日志打印函数的行号当业务出错点;先处理确切 FATAL,再判断 FPS。 2. 同一角色、地图、画质、分辨率、前台状态下:主城站立约 30 秒 → 战斗约 20 秒 → 回城站立约 60 秒。记录三个时刻,保留正常库对照,避免把后台限帧当性能回退。 3. 只需复现 2026-09-16 的原问题时,可在备份后的专用测试副本使用历史 ver-27;不要覆盖当前正式库。打包外端须重新打包诊断程序,旁放 Game.lib 不会替换内嵌库。 4. 若新问题依赖后来新增功能,必须把诊断逻辑定点移植到当前对应的最新不可变正式成品。不能为了套脚本回滚业务功能;构建新的诊断成品需按台账占用下一个 ver-N。此次 ver-28 选 ver-24 是用户明确要求剔除三次诊断的特例。 5. 先看 SAMPLE 的地图更新/绘制/UI/事件等阶段,再看同一 seq 的 FUNCS 与 HOOKS 是否确实接入。次数/包含ms/自身ms/单次最大ms 中嵌套包含耗时不能相加;应结合调用次数和每次耗时判断。 6. 定位热点后只优化有证据的函数,使用合成数据做语义/开销计数对照,再让相同角色复测。完成后恢复正式无插桩库,不能只把输出关掉而长期保留包装成本。
禁止默认新增每帧/每次伤害日志、全量存档打印、全树扫描或强制 GC。日志分享前脱敏;不复制认证令牌、角色存档等敏感内容到诊断报告。FPS 低但所有 Lua 阶段都短时再检查原生渲染、驱动、系统调度与后台限帧,不能强行归因业务。
可复用逻辑与测试入口
- 阶段采样:
tools/build_heimei_ver25.py的 instrument;助手源码analysis_output/Heimei-EG-lua_ver-25-performance-diag/source/perf_factory.lua。 - 函数细分:
tools/build_heimei_ver26.py及对应输出目录 source;固定白名单、协程独立计时栈、包含/自身耗时、异常重抛、nil/多返回值、停用恢复原入口。 - 低频定点方式:
tools/build_heimei_ver27_point.py,只修改两个间隔/上限立即数与标识,不重建其他逻辑;不能盲目套用原型索引。 - 回归:
tools/test_perf_ver25.py/.lua,tools/test_perf_ver26.py、test_perf_ver26_detail.lua、test_perf_ver26_regression.lua,tools/test_heimei_ver27_point.py和test_perf_ver27_point.lua。原生夹具在tools/fixtures/perf_ver25/、perf_ver26/。 - 热点修复:
analysis_output/perf_hotspot_20260916-fashion-pet/的 before/after、66 项定点断言、validation.json;正式测试tools/test_perf_fashion_pet.py/.lua。
上述历史构建/发布脚本硬编码旧底座、版本、路径和最高编号断言,用于审阅复用逻辑,不可直接重跑发布,也不可只替换版本字符串。移植前逐项更新底座及 SHA、下一编号、目标原型/索引、源表、预期原型数量、横幅、精确差异白名单、测试通过标识、输出路径、收据和 README。主循环新参数采集仍要保留原逻辑 dt 截断。
闭包审计必须沿原父链验证上值名称/描述符,内部 SystemDat 等不能变成全局。测试置同名全局为 nil、注入独立哨兵;编译通过不等于运行正确。新库须严格解析/标准语法、双向转换、精确差异、反向恢复逐字节等于底座,并保护全部历史交付和活动库。临时原生客户端要独立目录、隐藏启动,只结束自己创建的进程,用后清理;保留正式测试与日志证据。
本次时装与灵宠案例
根因是热路径计算方式,而非属性公式:时装每次属性刷新都 Save.export() 整档复制;灵宠 getter 将已正确的等级/经验等再次写入保护表,反复触发复制/加密/失效。修复为仅深复制 Save.get("时装") 子表(保留独立快照)以及灵宠仅缺字段/纠错时写回(保留可写代理和数值范围/整数子类型)。未改保护模块、反作弊或玩家存档。
66 项隔离检查中,100 次正常读取:时装整档导出 100→0 次,灵宠保护写入 800→0 次。随后用户反馈“好像不卡了”,日志 G:/DM3-longZhiCQ/mir3meiying2/Log/game.20260916.log 的 15:07 会话对比 14:50 会话,连续战斗 seq 5/6 的观测如下:
| 指标 | 优化前 | 优化后 |
| 战斗原生 FPS 均值 / 最低采样 | 41.18 / 26 | 55.76 / 49 |
| 地图逻辑每帧均值 | 8.96 ms | 3.50 ms |
| 主角属性计算次数 / 合计 | 163 / 4679 ms | 206 / 406 ms |
| 时装属性合计 | 2399 ms | 10 ms |
| 灵宠属性合计 | 2192 ms | 22 ms |
| Save.export 调用次数 | 175 | 0(HOOKS 已接入,FUNCS 无调用条目) |
主角属性单次约 28.71→1.97 ms。两个时段调用次数不同,不能仅凭合计判定等负载;十秒汇总不是逐帧分位数。用户主观与日志都支持明显改善,不据此宣称所有瞬时卡顿消失,仍有零星长帧。对应防回退规范已写入前端根 AGENTS.md。
更新记录
| 日期 | 适用版本/成品 | 变化 |
| 2026-09-16 | ver-25/26/27 诊断归档;ver-28 正式库交付配套 | 归档三轮用途、代码/测试入口、移植约束、空装备边界与时装灵宠修复/用户复测证据;文档归档不另占引擎编号。 |
