解释Bank与Event在FMOD热更中的差异
解读
面试官问的不是“Bank 和 Event 是什么”,而是“在热更新场景下,两者的差异会给 Unity 客户端带来哪些落地层面的坑与对策”。国内项目普遍把 FMOD 作为“资源”而不是“代码”来热更,因此必须回答:谁可以热、谁必须重启、谁会影响包体、谁会影响内存,以及如何在 iOS/Android/小游戏平台过审。
知识点
- Bank 是二进制资产文件(.bank),包含 Event、Sample、Metadata、DSP 设置;Event 只是 Bank 里的逻辑入口。
- Bank 的加载粒度是文件级,Event 的触发粒度是对象级。
- Unity 端通过
RuntimeManager.LoadBank把 Bank 装进内存,之后才能RuntimeManager.CreateInstance出 Event。 - Bank 一旦加载,内存里就占死,卸载必须等所有引用归零;Event 实例可以即时释放。
- 国内热更框架(Addressables、HybridCLR、YooAsset)只能把 Bank 当普通资源下载,不能对 Bank 内部做差分;Event 不需要单独下载,只要 Bank 更新即可。
- iOS 的 JIT 限制与 Android 的分包装载(Play Asset Delivery) 都不影响 Bank,但 Bank 大于 150 MB 会被 App Store 拒绝“蜂窝下载”。
- 微信/抖音小游戏平台不支持文件系统随机偏移读取,Bank 必须整包打进 StreamingAssets,热更时需重新启动小游戏内核,做不到“无感知”热更。
- Bank 更新后,旧 Bank 里正在播放的 Event 不会自动迁移,必须写“交叉淡入淡出”逻辑,否则玩家会听到瞬间静音或爆音。
答案
Bank 与 Event 在 FMDO 热更中的差异可以归结为“资产粒度”和“生命周期”两点:
-
可热更单元不同
Bank 是热更的最小单元,Event 只是 Bank 内的符号;策划想新增一个 Event,必须重新打包并下发整个 Bank,不能只推一个“Event 文件”。 -
加载与卸载时机不同
Bank 通过LoadBank一次性载入内存,占用常驻块,卸载需调用UnloadBank并保证所有 Event 实例引用为零;Event 通过CreateInstance动态生成,随用随扔,对内存冲击小。 -
版本兼容性策略不同
热更后的 Bank 如果修改了 Event 的 GUID 或参数结构,旧代码调用会抛 EVENT_NOT_FOUND;因此国内项目普遍在打包脚本里固化 Event 的 GUID,并给 Bank 做“版本号 + 哈希”文件名,防止旧包误加载。 -
平台合规差异
iOS 超过 150 MB 的 Bank 必须拆包,使用 On-Demand Resource;Android 通过 Play Asset Delivery 把 Bank 设为 fast-follow。小游戏平台则只能整包重启,做不到真热更。
一句话总结:Bank 是“文件级”热更,Event 是“对象级”使用;热更成本在 Bank,运行成本在 Event。
拓展思考
如果项目要求“战斗期间后台静默替换技能音效”,可落地方案是:
- 预先把技能音效拆到独占 Bank(skill_bank_v1、skill_bank_v2),体积控制在 30 MB 以内;
- 使用 Addressables 下载新 Bank 后,先 LoadBank(new),再对所有已暂停的 Event 实例做 FadeOut,完成后 UnloadBank(old),实现“交叉淡入淡出”无感知切换;
- 在 Android 侧开启 Play Asset Delivery – Fast Follow,iOS 侧把 Bank 拆成 ODR Tag,小游戏侧则直接提示“下一场战斗生效”,避免内核重启打断体验。