解释Bank与Event在FMOD热更中的差异

解读

面试官问的不是“Bank 和 Event 是什么”,而是“在热更新场景下,两者的差异会给 Unity 客户端带来哪些落地层面的坑与对策”。国内项目普遍把 FMOD 作为“资源”而不是“代码”来热更,因此必须回答:谁可以热、谁必须重启、谁会影响包体、谁会影响内存,以及如何在 iOS/Android/小游戏平台过审。

知识点

  1. Bank 是二进制资产文件(.bank),包含 Event、Sample、Metadata、DSP 设置;Event 只是 Bank 里的逻辑入口
  2. Bank 的加载粒度是文件级,Event 的触发粒度是对象级
  3. Unity 端通过 RuntimeManager.LoadBank 把 Bank 装进内存,之后才能 RuntimeManager.CreateInstance 出 Event。
  4. Bank 一旦加载,内存里就占死,卸载必须等所有引用归零;Event 实例可以即时释放。
  5. 国内热更框架(Addressables、HybridCLR、YooAsset)只能把 Bank 当普通资源下载,不能对 Bank 内部做差分;Event 不需要单独下载,只要 Bank 更新即可。
  6. iOS 的 JIT 限制与 Android 的分包装载(Play Asset Delivery) 都不影响 Bank,但 Bank 大于 150 MB 会被 App Store 拒绝“蜂窝下载”。
  7. 微信/抖音小游戏平台不支持文件系统随机偏移读取,Bank 必须整包打进 StreamingAssets,热更时需重新启动小游戏内核,做不到“无感知”热更
  8. Bank 更新后,旧 Bank 里正在播放的 Event 不会自动迁移,必须写“交叉淡入淡出”逻辑,否则玩家会听到瞬间静音或爆音。

答案

Bank 与 Event 在 FMDO 热更中的差异可以归结为“资产粒度”和“生命周期”两点:

  1. 可热更单元不同
    Bank 是热更的最小单元,Event 只是 Bank 内的符号;策划想新增一个 Event,必须重新打包并下发整个 Bank,不能只推一个“Event 文件”。

  2. 加载与卸载时机不同
    Bank 通过 LoadBank 一次性载入内存,占用常驻块,卸载需调用 UnloadBank 并保证所有 Event 实例引用为零;Event 通过 CreateInstance 动态生成,随用随扔,对内存冲击小。

  3. 版本兼容性策略不同
    热更后的 Bank 如果修改了 Event 的 GUID 或参数结构,旧代码调用会抛 EVENT_NOT_FOUND;因此国内项目普遍在打包脚本里固化 Event 的 GUID,并给 Bank 做“版本号 + 哈希”文件名,防止旧包误加载。

  4. 平台合规差异
    iOS 超过 150 MB 的 Bank 必须拆包,使用 On-Demand Resource;Android 通过 Play Asset Delivery 把 Bank 设为 fast-follow。小游戏平台则只能整包重启,做不到真热更。

一句话总结:Bank 是“文件级”热更,Event 是“对象级”使用;热更成本在 Bank,运行成本在 Event。

拓展思考

如果项目要求“战斗期间后台静默替换技能音效”,可落地方案是:

  1. 预先把技能音效拆到独占 Bank(skill_bank_v1、skill_bank_v2),体积控制在 30 MB 以内;
  2. 使用 Addressables 下载新 Bank 后,先 LoadBank(new),再对所有已暂停的 Event 实例做 FadeOut,完成后 UnloadBank(old),实现“交叉淡入淡出”无感知切换;
  3. 在 Android 侧开启 Play Asset Delivery – Fast Follow,iOS 侧把 Bank 拆成 ODR Tag,小游戏侧则直接提示“下一场战斗生效”,避免内核重启打断体验。