卡顿诊断版 Game.lib
归档入口:三轮诊断复用记录。正式 ver-28 明确排除 ver-25/26/27 的诊断插桩和输出;下文为独立历史诊断库行为,不表示正式库默认开启诊断。
当前低频诊断成品:Game_Heimei-EG-lua_ver-27_低频诊断.lib,以不可变 ver-26 为底座,仅调整采样输出间隔、组数上限和标识。ver-25 是第一轮阶段诊断,ver-26 新增函数计时,字段定义沿用。继承天气 PNGZ 与极高画质等已有功能,不是已确认的战斗卡顿修复版。不自动部署或覆盖正式库。
使用方法
1. 在开发端或测试副本中备份 Dat/Game.lib,把诊断库复制为该位置的 Game.lib,重新启动。已打包外端把库嵌在程序内,必须用诊断库重新打包测试程序,不能仅在外端旁边放一个同名文件。 2. 本轮启动横幅应显示 Heimei-EG-lua / ver-27 by 黑妹。保持相同画质、窗口大小和同一个角色,窗口放在前台,不必打开 F12 调试面板。 3. 先不战斗约 30 秒,再进行容易引发卡顿的战斗;FPS 降低后停战站立约 60 秒。有条件再切图观察是否恢复。记录战斗开始、明显卡顿、切图的大致时刻。 4. 退出后保留本次客户端工作目录的 Log/game.年月日.log。本轮搜索 HMP27|START、HMP27|SAMPLE、HMP27|FUNCS 确认诊断生效;历史 ver-25/ver-26 分别为 HMP25/HMP26。将完整日志及复现时刻交给开发者;分享前注意日志中其他业务代码可能记录账号信息。 5. 测试后恢复备份的正常库;外端恢复原测试程序。不要将诊断版长期作为正式发布版本。
诊断默认自动开启,不需要修改 App.lua、定义内部全局或调用新增 API。ver-27 按截断前原生 dt 累计,每约 10 秒一组记录,最多 180 组(正常情况下约 30 分钟),相同运行时长的常规输出组数降低约 80%;ver-26 为 2 秒/900 组。每组仍有 SAMPLE、FUNCS、HOOKS 三行,达到上限写 HMP27|STOP。长时间阻塞后只写一组,不补刷多组日志。重启才能继续;日志写入失败会停用诊断并恢复仍属于本诊断器的函数入口,不阻断业务。ver-27 不改变函数计时包装和每秒接入检查的频率。
下文 HMP26 字段格式在 ver-27 中一致,仅前缀改为 HMP27。2026-09-16 的空装备格 FATAL 修复位于 mir3meiying2 的两个游戏脚本,不包含在本库中;原生日志明确指向 装备穿戴属性计算 的空道具访问,不能把此次崩溃等同于已定位的战斗低 FPS 根因。
ver-26 修正与函数级计时
dt_max_ms / slow50改用原生截断前 dt;新增logic_dt_max_ms表示游戏实际收到的逻辑 dt,原有 30 ms 截断不变。ver-25 在截断后统计,slow50=0不能说明没有长帧,采样窗口也可能比墙钟两秒更长。actors改为当前地图npcList条目数量,包含该列表仍保留的死亡或待处理单位,不等同于存活怪物数。原 ver-25 的actors是空间格子索引键数,现改名actor_cells;空格子索引可保留,不能据此判断怪物泄漏。- 原
scanned_objects/object_buffs/object_events/object_children扫的是非 NPC 物件组;ver-26 改为扫描npcList,字段改为scanned_npcs/npc_buffs/npc_events/npc_children,最多 256 个 NPC。单独的objects仍表示原物件组数量。
HMP26|FUNCS 中每项的格式固定为:
函数标识=调用次数,包含耗时ms,自身耗时ms,单次最长ms,异常次数
Save.export=80,957.000,957.000,180.000,0
示例仅来自离线注入延迟,不是玩家实测。包含耗时包含子调用;自身耗时只扣除同一协程内已经接入诊断的子调用,并非逐行 CPU 计时。父子包含耗时不能相加。同名函数递归调用按实际完成次数统计;协程挂起/恢复的跨窗口调用在完成时入账,耗时可能包含挂起等待,不能当作同步主线程占用。
HMP26|HOOKS 的 bound 明确列出成功接入的函数,missing 列出本次未找到的白名单函数;FUNCS 中没有某项也可能只是本窗口未调用。每约 1000 ms 原生运行时间检查一次函数/表是否重建,不调用业务函数探测、不导出数据、不记录参数或返回值内容。
| 标识 | 目标函数 |
Save.export / Data.export | 对应保护表的导出方法 |
hero_attr / hero_damage | ZhuJiao.主角属性计算 / 伤害计算 |
npc_damage / npc_death | ShiJian.伤害计算 / 怪物死亡公共处理 |
fashion_attr / fashion_save | Quanju.时装属性缓存刷新 / 时装存档返回 |
system_tick | Quanju.系统时钟_1000 |
hero_recover / afk_tick / target_ui / hero_shield | ZhuJiao.主角舒适度恢复 / 挂机数据时钟 / 怪物头像更新 / 同步主角护盾到引擎 |
fashion_spirit / realm_attr | Quanju.幻灵主角属性加成返回 / 境界_属性总加成 |
auto_recycle / protect_tick / combat_settings | L设置.背包自动分解时钟 / 保护设置时钟 / 战斗设置时钟 |
monster_spawn / boss_track | L怪物.怪物刷新时钟 / L历练.BOSS追踪时钟 |
collection_ui / collection_attr | L藏品.刷新界面 / 取总加成 |
pet_tick / pet_ui / world_boss_ui / pet_attr | L灵宠.灵宠战斗时钟 / 刷新灵宠界面 / 刷新世界BOSS窗口 / 取属性加成 |
server_time / daily_tick | L福利.更新服务器时间 / 结算每日重置数据 |
dungeon_tick / scene_presence | L副本.副本系统时钟 / Legend.ScenePresence.Update |
白名单共 30 项,不涵盖全部业务函数。只接入全局表上已有的原始函数字段,不触发保护表的读写元方法;停用或目标表重建时,只恢复仍指向本诊断包装的字段,不覆盖业务后来替换的函数。业务提前保存的函数别名或内部局部调用可能绕过包装;未计时子函数仍包含在父函数自身耗时中。
函数包装保留不定参数、nil、多返回值及原返回对象,协程状态分别计时;业务异常经 pcall 清理诊断栈后上抛原错误对象,异常栈会增加诊断层。函数身份和调用栈因此会发生临时变化,不声称完全无侵入。每协程最多计时 64 层,超过后透传执行并累计 depth_skipped;建议仅用于本轮复现,完成后恢复正常库。
日志含义
| 字段 | 含义和边界 |
fps_avg / fps_min / dt_max_ms / slow50 | 窗口内原生 FPS 输入的平均/最小值、最长 dt、dt 至少 50 ms 的帧数;不是精确百分位统计。ver-25 的 dt 在截断后,ver-26 已修正。 |
focus / focus_frames | 采样时前台状态、窗口内获得焦点的帧数;用于排除后台限帧干扰。 |
draw_avg / draw_max / api_avg | 主循环原生输入的 DrawCall 和 API 次数统计;不等于显卡耗时。 |
native_fun_raw | 原生 funTime 输入均值,保留原始单位,未擅自标为毫秒。 |
lua_avg_ms / lua_max_ms | 插桩主循环的 os.clock 计时;包含期间调用的原生接口,不等于纯 Lua 指令时间。 |
xxx_ms=平均/最大 | 各阶段每帧计时,单位 ms;各阶段最大值不一定来自同一帧,不能相加当作最长帧。 |
prev_report_ms | 上一次计数、格式化和写日志所用时间;报告自身不计入当次主循环计时,但可能影响下一帧 dt。 |
lua_mb / lua_delta_mb | 当前 Lua 内存及相对上次报告的变化,不包括全部原生/GPU 内存;自然 GC 可使其下降。 |
nodes_created_total / textures_created_total | 原引擎累计创建计数,绝不是当前存活数,增长本身不能证明泄漏。 |
objects / actors / actor_cells / projectiles / skills / lightning / ground_damage | 当前地图相应容器条目数;actors 与 actor_cells 的版本口径见上文,不把多个容器相加当作互不重叠对象。 |
tweens / tasks / engine_events / map_events / jump_text | 当前补间、任务、引擎/地图事件、飘字队列条目数。 |
hero_buffs / hero_events / hero_children / hero_trail | 当前主角状态、定时事件、附属节点、拖尾片段数量,不导出人物名或属性存档。 |
scanned_npcs / npc_buffs / npc_events / npc_children | ver-26 当前地图 NPC 中最多 256 项的状态、事件、附属节点数组长度合计;不代表全场景总量。 |
scan_clipped=1 / 2048+ | 分别表示物件扫描被截断、单个计数容器达到扫描上限;不得当作精确总量。 |
engine_event_top / map_event_top / hero_event_top | 最多扫描前 512 项、最多保留 32 种名称,再输出前三种事件名及频次;只作候选线索。 |
slow_eventN=名称:次数:合计ms:最大ms | 本窗口内单次达到 4 ms 的引擎定时事件回调,最多保留 32 种名称并输出合计耗时前三名;不涵盖 NPC/地图内部全部回调。 |
path_calls_delta / path_ms_delta / path_reset | 当前地图寻路计数及时间的采样增量;首次、换图或计数下降时置 reset 并从下一窗口计增量。 |
阶段依次为:setup(运行态更新)、tween(补间)、tasks(任务队列)、map_run(所有已加载地图更新)、map_draw(当前地图绘制及渲染目标调用)、text_buff(调试信息/冷却/状态图标/提示与飘字更新)、events(引擎事件)、ui_run(顶层及窗口更新)、ui_draw(置顶状态、气泡、菜单、顶层等绘制)、network(内置 TCP 客户端 Run)、cursor(鼠标指针)、gc_tail(原有周期性 GC 区段)。
判断边界
- 战斗后某阶段耗时和对应队列持续增长,才有依据继续定点检查相关对象清理、事件重复注册等;单条日志不能直接判断根因。
- FPS 很低但所有插桩阶段都很短时,仍需考虑原生引擎、显卡/驱动、系统调度、后台限帧等。此库不提供 GPU 专用计时、逐行调用栈或角色存档故障修复。
- os.clock 的实际计时行为和分辨率受引擎运行时实现影响,
0.000不代表绝对没有耗时;计数扫描有明确上限,不做整棵对象树遍历,不强制新增 GC,不自动删除事件、状态、特效或缓存。 - 诊断自身有开销;
prev_report_ms、正常库同场景对照和前后台信息应一起看。停止诊断后仍保留少量空操作调用,完成排查应恢复正常库。 - 诊断汇总/日志异常不阻断业务;ver-26 的函数包装会清理计时栈并上抛原业务错误对象,见前述边界。内部对象通过原父闭包传递,不依赖同名全局。
验证状态
ver-25:结构、20,729 项隔离断言和真实 App.exe 11 条汇总通过。2026-09-16 用户已提供问题角色实测日志:主城约 53 FPS、战斗最低记录 17 FPS,地图更新最长 678 ms,回城恢复;仅缩小热点范围,未确认具体根因。
ver-26:以 ver-25 为底座,仅替换诊断助手树和截断前采集入口、横幅;1762 Proto,原主循环指令不变,严格解析/语法/捕获链/精确差异/反向逐字节还原通过。20,729 项主循环回归与 45 项精细契约断言通过;标准 Lua VM 的 100,000 次空函数测试,包装额外开销样本约 0.350 微秒/调用,仅供参考。真实 App.exe 离线测试得到 5 组采样,识别模拟导出 180 ms、原生帧间隔约 184 ms 和原逻辑 dt 不超过 30 ms;未写保护数据。临时客户端已清理,玩家真实问题尚待 ver-26 采样,不能宣称已修复。
更新记录
| 日期 | 适用版本 | 变化 |
| 2026-09-16 | ver-25 诊断专用 | 新增自动低频性能日志、分阶段计时、当前角色/场景容器数量、慢引擎事件与日志上限;不调整业务效果。 |
| 2026-09-16 | ver-26 精细诊断 | 新增 30 项函数白名单的包含/自身耗时和接入覆盖记录;修正截断前帧间隔、NPC 与空间格子计数;保留逻辑 dt 上限及原业务结果。 |
| 2026-09-16 | ver-27 低频诊断 | 定点改为 10 秒/组、最多 180 组,前缀 HMP27;不改计时包装、业务逻辑或闭包。仅做定点机器测试,未作全局复核或新一轮玩家实测。 |
| 2026-09-16 | ver-25/26/27 归档,ver-28 配套 | 增补三轮复用文档、时装/灵宠根因及后续用户日志对照;此前验证状态保留为当时记录,后续结果以复用记录为准。 |
