使用 TTAssetBundle 优化内存
收藏
我的收藏内存问题
在 Unity WebGL 小游戏环境中处理 AssetBundle 加载时,我们无法利用 App 游戏中常用的
AssetBundle.LoadFromFile()
等依赖本地文件系统的加载方式,而是需要使用 UnityWebRequest
等通过网络的加载接口。通过
UnityWebRequest
加载 AssetBundle 时,下载或从本地缓存中读入的 AssetBundle 文件会完整拷贝到 Unity Heap 内存,在 Unload 之前额外占用 Unity Heap。而由于 Unity Heap 一旦超额分配便无法从 JS Heap 中释放,将其控制在更小范围内有利于控制整体进程内存,降低崩溃率。
解决方案
TTAssetBundle 接口通过打通 Unity 内存文件系统和小游戏本地缓存文件系统接口,在加载 AssetBundle 时内部使用 LoadFromFile() 仅打开文件流,在 LoadAsset 时通过文件描述符按需读 取 AssetBundle 的包内资源,可以节省与 AssetBundle 文件大小相当的内存。
使用说明
版本要求
开发工具:
- •StarkSDK 5.52.10 及以上
- •StarkSDK Unity Tools 3.31.2 及以上
- •Unity 2021.3 及以上
宿主:
- •抖音/抖音极速版 29.2.0 及以上,暂不支持头条、番茄。
- •不支持的版本/宿主上,会 fallback 为类似原本
UnityWebRequest
加载实现,仍可正常加载到资源。
构建配置
要通过 TTAssetBundle 加载的资源,其域名都必须配置在“缓存资源域名列表”中。这一配置是为了 AssetBundle 资源文件能够被正确存入小游戏文件缓存中,供相关接口后续按需读取。
加载 AssetBundle
加载 AssetBundle 代码示例:
using StarkSDKSpace; UnityWebRequest request = TTAssetBundle.GetAssetBundle(url); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { Debug.Error(request.error); } else { AssetBundle ab = (request.downloadHandler as DownloadHandlerTTAssetBundle)?.assetBundle; ab.TTUnload(true); // 使用 TTAssetBundle 加载的资源,必须调用 TTUnload() 方法才可彻底卸载。 }
使用 Addressables
如果项目使用 Addressables 管理资源,可以通过替换 Provider 以使用 TTAssetBundle。
- 1.引入适配的 Provider:
- ◦在 StarkSDK 目录下找到 TTAssetBundleProviders.cs.txt 文件(通常在 Assets/Plugins/ByteGame/com.bytedance.starksdk/WebGL/AssetBundle 目录下)。
- ◦将其拷贝到工程中,并更名为 TTAssetBundleProviders.cs(移除扩展名 txt)。
- 2.设置 Addressable Asset Group 的 Providers:
- ◦Asset Provider 设为 Assets from TTBundles Provider
- ◦AssetBundle Provider 设为 TTAssetBundle Provider
- ◦Use AssetBundle Cache 设为 False
- 3.重新导出 Addressables 资源、打包小游戏。
注意事项
- •TTAssetBundle 主要能够节省 Unity Heap 内存的使用,而 Unity Heap 内存通常是预先分配的。建议开发者完成接入后,在打包工具中重新评估(适当降低) Unity Heap 预留内存大小,以取得更好的整体进程内存收益、降低崩溃率。推荐对内存有严格要求的中重度游戏接入使用。
- •加载过程中的 AssetBundle 文件会在 JavaScript 内存中保留一份完整的文件缓存以保证载入性能。内存文件缓存中的文件超过 5s 未被读取或缓存占用超出 128MB 上限时,将按 LRU 清理最久未被读取的 Bundle。被清理的 AssetBundle 下次读取时将重新从磁盘读入,建议开发者及时调用 TTUnload() 卸载不使用的 AssetBundle。自动清理的阈值支持在 StarkBuilderSettings 中配置。
- •Android Native 方案下也可以使用该接口,但内部会 fallback 为使用
AssetBundle.LoadFromMemory()
实现加载,没有任何内存和加载效率上的收益。开发者可以根据需要自行判断是否在 Native 方案下替换加载接口。