You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
AdLike2048/docs/方案-加载性能优化.md

8.6 KiB

方案:加载性能优化(冷启动 / 静默下载 / 点击优先)

日期:2026-09-11
关联:docs/性能打点说明.md、assets/mx/module/res/*
打开 / 引用 / 分包所有权 以 方案-资源与UI生命周期.md 为准(2026-09-14)。

1. 问题与证据

现有启动链已具备 Phase / LoadScheduler / PreloadPredictor,但和「最快进首页 + 后台静默下载」目标不一致:

现状 后果
Boot 并行拉 icons、popCommon 与 home 抢带宽,首进/冷启动变慢
preLoadResPakg 对弹窗做 bundle.load + addRef 静默路径占内存,且曾与进战 clearResPkg 并发导致贴图失效(战斗 silent warm 已关闭,保留)
LoadScheduler silent 挂在 AFTER_UPDATE 后台 IO 吃主循环帧预算
openPanel 不暂停 silent 玩家点页面仍可能被后台下载拖慢

2. 原则

  1. 真正进内存的加载按需:进首页只 load 首页能画出来的资源;点哪个页面就 load 哪个。
  2. 静默 = 下载分包 / bundle.preload:不 addRef、不进战斗资源包内存、可随时丢弃。
  3. 静默与主循环解耦:用 setTimeout 泵 silent,不走 Director.EVENT_AFTER_UPDATE。
  4. 玩家打开 / 自动弹窗 / 进战 = 最高优先级:beginUserLoad 立刻停发新的 silent;进行中的原生 loadBundle 无法取消,但不继续排队。
  5. 分档只调激进度与表现,不 fork 业务:下载并发/间隔用 MemoryProfile;战斗特效用已有 DeviceProfile。
  6. 不恢复战斗资源包的内存预热(scheduleBattleWarm('silent') / preLoadLevelRes 保持关闭),避免贴图生命周期回归。

3. 阶段

Boot(最小)
  First + Comm + icons_boot + home + BootRes
  表:Const / Item / Rank / Level(首页展示与点开始)
    │
    ▼
first/comm/home 分包落地(BootRes 仍在本包 load)
    │  立刻静默 loadBundle(icons),不阻塞、不 acquire
    ▼
Hall 可交互(Home 已打开)
    │  延迟 2 帧,避免和首页首帧抢 IO
    ▼
Silent A:icons 优先(已在下则跳过),再战斗分包(loadBundle,不 acquire、不 load 资源)
  heros / battleGame / battleMap / battleGameMonster / battleHero / popBattle
  (不含已删除的 role / mechanismEffect;大厅名单只含磁盘上有预制的页面)
    │
    ▼
Silent B:下载页面分包 + preload 弹窗预制
  match 优先,再大厅页/弹窗
    │
    ▼
玩家点击 / 自动弹窗 / 进战
  beginUserLoad → 暂停 silent → 按需 loadPrefab / loadResPakg(进战最小包)
    │
    ▼
BattleGame 已打开
    │
    ▼
Silent C:局内弹窗 preload(暂停优先)+ 受击/死亡/武器目录 load
  不 addRef;点开弹窗仍走 openPanel 最高优先

新玩家与老玩家冷启动同一条最小 Boot;老号缓存命中后 loadBundle 更快,但仍不在 Boot 里拉战斗包和全量弹窗。

进战最小包:地图、出怪口、模板/字块/营地、本关血条与开场怪、状态特效、飘字、怪物皮肤目录、英雄体/攻效/buff 目录。
进局后再补:popBattle 弹窗、受击/死亡、组合武器目录。BGM 由 playBgmBattle 按需拉。

4. 五维影响

加载 内存 FPS CPU 发热
首进/冷启动少下 icons+popCommon,进首页更快 大厅不再把 HallWarm 整包 addRef silent 离开主循环,首帧更稳 后台 IO 错峰 低档拉长 silent 间隔

补偿:段位图标走 SpriteLoad 按需拉 icons;点设置/体力等首次需等 popCommon(随后 silent 会补下)。进战 loadResPakg 只解最小包;局内弹窗/受击未预完时按需 load。

5. 资源所有权(不可违反)

  • Silent loadBundle 不 BundleLifecycle.acquire,避免 owner=res 钉死战斗包,导致退战卸不掉。
  • 进战 loadResPakg / openPanel 仍按原 owner 登记;释放顺序不变:teardown → onDestroy → waitFrames → clearResPkg / releaseBattlePhase。
  • 进战 abortHallSilentDownload + clearSilentQueue,禁止大厅 silent 与 loadResPakg(clear) 并发。
  • 局内 silent 不 acquire、不进 BattleRes;退战先 abort 再 teardown → clearResPkg / releaseBattlePhase。
  • 战斗中允许 silent(BattlePhysicsGate 不再暂停);切后台 / 内存降档仍暂停。

6. 回归

  • 清缓存冷启动:新号 / 老号都能进 Home,段位图可晚一拍出现。
  • 进 Home 后立刻点开始:匹配页优先加载,不受 silent 阻塞。
  • 进 Home 后立刻点神将/设置:该页优先,silent 停发。
  • 战斗 ↔ 大厅 ≥3 次:无缺贴图 / Spine;退战战斗包仍可卸。
  • 进战立刻点暂停/结算/Boss:未预完也能按需打开。
  • 首召 / 首波:英雄体、怪物皮肤、状态特效仍在进战包内。
  • 弱网:silent 失败只打日志,不 recoverHome。

7. 线上卡 loading / 失败后打不开页面

老项目就有:assetManager.loadBundle / bundle.load 无超时、同名可并发、回调可能永不回来。
昨天把 popCommon / 局内弹窗 / 战斗包改成按需后,这条路径变成线上主路径,缺陷被放大。

缺陷 后果
静默 loadBundle 与玩家 loadBundle 同名并发 小游戏上第二回调可能永不触发,loading 一直转
openPanel 用 _panelOpenInflight 等第一次打开 第一次挂死后,同页面后续点击永久等待
recoverHome 只 endUserLoad 一次、再 enterMain 门闩泄漏;Home 再挂则死循环卡 loading
closeAllPanel 清 inflight 却不 resolve 已 await 的打开再也结束不了

修复:BundleLifecycle.ensureLoaded 同名合并 + 20s 超时;加载中禁止 removeBundle;openPanel 超时失败并 abortInflightOpens;recoverHome 重置用户加载门闩,连续失败改重启提示。

2026-09-18: 根因是 openPanel 与静默预载对同一预制双飞原生 load,回调丢失后失效缓存被当成永久失败。预制必须走 ResourcesManager.loadRes 合并。进战仍释放 HallWarm 预制;popCommon zip 常驻;回大厅先 decode 再静默战斗包。

8. 新用户首局缺资源(2026-09-12)

首进失败、再进正常:不是贴图坏了,是冷启动优化把「齐套」拆成后台补齐,首局用到时还没齐。

缺陷 后果
Hero/Weapon/Text/Monster1 延后加载,getTableData 只点火不阻塞 首局组装进战包漏血条/特效;AI 武器全 miss
loadBundle 超时 finish(null) 并清 inflight 新用户首下未完就二次并发,回调丢失
静默超时把分包打进 _silentMissBundles 后续永远跳过该包
预载 evict 后 loadResPakg(fresh=false) 复用已释放 bundle.get 血条/皮肤 getNode 空,再进因缓存命中又好了
preLoadResPakg 失败仍标 warm 完成 进战以为已预热,跳过强制重载

修复:开战前 ensureBattleTables 再组包;超时不拆原生 inflight;warm 失败才 fresh 重载;血条三种预制固定进最小包。

9. 匹配页卡死(2026-09-12)

抖音首包 preLoadResPakg 常超过 30s。匹配门闩 awaitBattleWarm 超时抛错后仍进战,进战再次 await 同一 Promise,超时走 _failBattleEnter,首页已关、匹配页不关。

修复:匹配页只点火 warm,门闩只等表 / 神将包 / BattleGame 预制;awaitBattleWarm 超时返回 false 不抛;进战超时改 loadResPakg,不失败离场。battleWarmTimeoutMs 与 dirTimeoutMs 对齐为 60s。

10. 首局加载过久(2026-09-12)

抖音新包点开始要 30s+,不是网单独慢,是下载被自己掐掉再重来:

缺陷 后果
战斗分包走 silent 队列,tier0 并行 1、间隔 120ms heros→battleGame→地图…串行下
点开始 abortHallSilentDownload + beginUserLoad 没开始的战斗包出队,匹配再从头下
warm 超时 abort + loadResPakg(fresh) 已下到一半的目录被 evict,再下一遍

修复:BootRes 完成后并行 ensureLoaded 战斗分包(不进 silent、点开始不停);进战 warm 仍在飞则 loadResPakg(fresh=false) 合并,禁止 evict 重来。

加载 内存 FPS CPU 发热
首页展示后战斗包已在下,首局少等一轮 zip 与原 silent 同包,不 addRef 首页首帧后才开火,不抢 BootRes 并行 loadBundle 峰值略升 低档可接受

回归:清缓存冷启动立刻点开始;在首页停 5s 再点;战斗↔大厅 ×3。