![](https://i-blog.csdnimg.cn/blog_migrate/ec1bff036cf1b56c684c257aca5e40b1.png)
assetbundles
Whether your application streams assets from a content delivery network (CDN) or packs them all into one big binary, you’ve probably heard of AssetBundles. An AssetBundle is a file that contains one or more serialized assets (Textures, Meshes, AudioClips, Shaders, etc.) and is loadable at runtime.
无论您的应用程序是从 内容交付网络 (CDN) 流式传输资产, 还是将它们全部打包到一个大的二进制文件中,您都可能听说过 AssetBundles 。 AssetBundle是一个包含一个或多个序列化资产(纹理,网格,音频剪辑,着色器等)的文件,可在运行时加载。
AssetBundles can be used directly or through systems like the Unity Addressable Asset System (aka Addressables). The Addressables system is a package that provides a more accessible and supported way to manage Assets within your projects. It is an abstraction on top of AssetBundles. While Addressables minimizes the direct interactions developers have with AssetBundles, it is helpful to understand how the usage of AssetBundles can affect memory usage. For an overview of the Addressables system, please refer to this blog post and this session from Unite Copenhagen 2019.
AssetBundle可以直接使用,也可以通过 Unity可寻址资产系统 (又称为可寻址对象)之 类的 系统使用 。 Addressables系统是一个软件包,提供了更易于访问和支持的方式来管理项目中的资产。 它是AssetBundles之上的抽象。 虽然“可寻址对象”将开发人员与AssetBundles的直接交互减至最少,但了解AssetBundles的使用方式如何影响内存使用量很有帮助。 有关Addressables系统的概述,请参阅 此博客文章 以及 Unite Copenhagen 2019的本次会议 。
Developers working on new projects should consider using Addressables rather than working with AssetBundles directly. If you are working on a project with an already established AssetBundles approach, the information here about how AssetBundles affect runtime memory will help you get the best possible results.
从事新项目的开发人员应考虑使用可寻址对象,而不是直接与AssetBundles一起使用。 如果您正在使用已经建立的AssetBundles方法进行项目,则此处有关AssetBundles如何影响运行时内存的信息将帮助您获得最佳结果。
内存丢失到内存缓存 (Losing memory to the memory cache)
When Unity downloads an LZMA AssetBundle using the WWW class (which is now deprecated) or UnityWebRequestAssetBundle (UWR), Unity optimizes the fetching, recompressing, and versioning of AssetBundles using two caches: the memory cache and the disk cache.
当Unity 使用 WWW类 (现已弃用)或 UnityWebRequestAssetBundle (UWR) 下载 LZMA AssetBundle时 ,Unity使用两个缓存优化对AssetBundle的获取,重新压缩和版本控制:内存缓存和磁盘缓存。
AssetBundles loaded into the memory cache consume a large amount of memory. Unless you specifically want to frequently and rapidly access the contents of an AssetBundle, the memory cache is probably not worth the memory cost. Instead, use the disk cache.
加载到内存缓存中的AssetBundle占用大量内存。 除非您特别想频繁且快速地访问AssetBundle的内容,否则内存缓存可能不值得花费内存。 而是使用磁盘缓存。
If you provide a version or a hash argument to the UnityWebRequestAssetBundle API, Unity stores your AssetBundle data into the disk cache. If you do not provide these arguments, Unity uses the memory cache. Note that Addressables uses the disk cache by default. This behavior can be controlled via the UseAssetBundleCache field.
如果您为 UnityWebRequestAssetBundle API 提供版本或哈希参数 ,则Unity会将您的AssetBundle数据存储到磁盘缓存中。 如果不提供这些参数,则Unity将使用内存缓存。 请注意,默认情况下,可寻址对象使用磁盘缓存。 可以通过 UseAssetBundleCache字段 控制此行为 。
AssetBundle.LoadFromFile() and AssetBundle.LoadFromFileAsync() always use the memory cache for LZMA AssetBundles. We therefore recommend using the UnityWebRequestAssetBundle API instead. If it is not feasible to use the UnityWebRequestAssetBundle API, you may use AssetBundle.RecompressAssetBundleAsync() to rewrite an LZMA AssetBundle on disk.
AssetBundle.LoadFromFile() 和 AssetBundle.LoadFromFileAsync() 始终对LZMA AssetBundles使用内存缓存。 因此,我们建议改为使用UnityWebRequestAssetBundle API。 如果使用UnityWebRequestAssetBundle API不可行,则可以使用 AssetBundle.RecompressAssetBundleAsync() 重写磁盘上的LZMA AssetBundle。
Internal testing shows that there is at least an order of magnitude difference in RAM between using the disk cache and using the memory cache. You must weigh the tradeoff in memory cost versus added disk space requirements and Asset instantiation time for your application.
内部测试表明,在使用磁盘缓存和使用内存缓存之间,RAM至少有一个数量级的差异。 您必须权衡内存成本与应用程序增加的磁盘空间要求和资产实例化时间之间的权衡。
To determine what effect the AssetBundle memory cache may have on your application’s memory usage, use a native profiler (our tool of choice is Xcode’s Allocations Instrument) to examine allocations from the ArchiveStorageConverter class. If this class is using more than 10MB of RAM, you’re probably using the memory cache.
为了确定AssetBundle内存缓存可能会对应用程序的内存使用产生什么影响,请使用本机探查器(我们选择的工具是 Xcode的Allocations Instrument )来检查ArchiveStorageConverter类中的分配。 如果此类使用的内存超过10MB,则可能是在使用内存缓存。
![](https://i-blog.csdnimg.cn/blog_migrate/e75481ca1b21a7e61fd19b94f52896cd.png)
Xcode’s Allocations Instruments showing the amount of memory used by the ArchiveStorageConverter class
Xcode的分配工具显示ArchiveStorageConverter类使用的内存量
找出您的AssetBundle实际加载了什么 (Find out what your AssetBundles are actually loading)
When building AssetBundles for large projects, do not assume that Unity by default will minimize the amount of duplicated information across them. To identify instances of duplicated data in the generated AssetBundles, you can use the handy AssetBundle Analyzer, written in Python by one of our colleagues in the Consulting & Development group. Used via the command line, the tool extracts information from generated AssetBundles, which is then stored in an SQLite database that features several useful views. You can then query the database using tools such as DB Browser for SQLite. This tool can help you find and resolve any inefficiencies in your build pipeline, whether you created bundles manually or via Addressables.
在为大型项目构建AssetBundle时,请不要假定默认情况下Unity会最小化它们之间重复信息的数量。 要在生成的AssetBundle中标识重复数据的实例,可以使用 由咨询和开发小组的一位同事用Python编写 的便捷的 AssetBundle Analyzer 。 该工具通过命令行使用,从生成的AssetBundle中提取信息,然后将其存储在具有多个有用视图SQLite数据库中。 然后,您可以使用诸如 DBite for SQLite之类的 工具查询数据库 。 该工具可以帮助您发现并解决构建管道中的任何低效率问题, 无论您是手动创建捆绑包还是通过Addressables创建捆绑包。
![](https://i-blog.csdnimg.cn/blog_migrate/01e80a32e7c5ed508c56f98cd7f2bdb7.png)
Analyzing the results from the AssetBundle Analyzer tool using DB Browser for SQLite
使用DB Browser for SQLite分析AssetBundle Analyzer工具的结果
Alternatively, check out the AssetBundle Browser tool, which you can download and integrate into your project straight away. Note that this tool provides similar functionality to Addressables, so if you are using Addressables, this tool is not relevant.
或者,签出 AssetBundle Browser工具 ,您可以 将 其 下载 并立即集成到项目中。 请注意,此工具提供了与可寻址对象相似的功能,因此,如果您使用的是可寻址对象,则此工具不相关。
The AssetBundle Browser tool allows you to view and edit the configuration of AssetBundles in a given Unity project and provides build functionality. It also provides some neat features, such as informing users about duplicated Assets that are being pulled due to dependencies, such as textures.
通过AssetBundle浏览器工具,您可以查看和编辑给定Unity项目中AssetBundles的配置,并提供构建功能。 它还提供了一些简洁的功能,例如通知用户有关由于依赖性(例如纹理)而被拉回的重复资产的信息。
![](https://i-blog.csdnimg.cn/blog_migrate/fdc15ad0f3a6e867fe2be8ef650e2f6b.png)
The AssetBundle Browser tool warns us about duplications due to dependencies being pulled by more than one bundle
AssetBundle浏览器工具警告我们有关由于多个包捆绑了依赖项而导致的重复
丢失内存以重复资产 (Losing memory to duplicate Assets)
When deciding how to organize your Assets into AssetBundles, you need to be careful about dependencies. Regardless of your AssetBundle topology, Unity makes a distinction between Assets that live inside the application binary (in or involving a Resources folder) and those that you need to load from AssetBundles. You can think of these two types of Assets as living in different worlds. It is impossible to create an AssetBundle that has a hard reference to the instance of an Asset inside the Resources folder world. To reference those Assets, Unity instead makes a copy of the Assets that it uses in the AssetBundle world.
在决定如何将资产组织到AssetBundles中时,您需要注意依赖关系。 不管您的AssetBundle拓扑如何,Unity都会区分应用程序二进制文件(位于或涉及Resources文件夹)中的资产与需要从AssetBundles加载的资产。 您可以将这两类资产视为生活在不同的世界中。 无法创建对Resource文件夹世界中的Asset实例具有硬引用的AssetBundle。 为了引用这些资产,Unity会复制它在AssetBundle世界中使用的资产的副本。
![](https://i-blog.csdnimg.cn/blog_migrate/ae48942383215ed122ab2281a747a424.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5ff42d8048a4af106ca0c03e5af329ed.png)
Two Components have a hard reference to the “logo” image. If these Components are serialized into different archives (bundled with the player or included in an AssetBundle), each will include their own copy of the image.
两个组件对“徽标”图像都有严格的参考。 如果将这些组件序列化到不同的存档中(与播放器捆绑在一起或包含在AssetBundle中),则每个组件都将包含自己的映像副本。
Take for example a game’s logo. The logo may be displayed in the UI of a loading scene while the game starts up. Because this loading screen must be shown before remote Assets are streamed to disk, you might include the logo Asset in the build so that it can be used immediately.
以游戏徽标为例。 游戏启动时,徽标可能会显示在加载场景的UI中。 因为必须在远程资产流式传输到磁盘之前显示此加载屏幕,所以您可能在徽标中包含徽标资产,以便可以立即使用。
This same logo is also used on an options panel in the UI, where users can select their language, sound preferences, and other settings. If this UI panel is loaded from an AssetBundle, then that AssetBundle will create its own copy of the logo Asset.
用户界面中的选项面板上也使用了相同的徽标,用户可以在其中选择其语言,声音首选项和其他设置。 如果此UI面板是从AssetBundle加载的,则该AssetBundle将创建其自己的徽标Asset的副本。
If both the loading screen and the options panel are loaded at the same time, both copies of the logo Asset will be loaded, which is a duplication that costs memory.
如果同时加载屏幕和选项面板,则将同时加载徽标资产的两个副本,这是一个重复操作,会占用大量内存。
The solution to this problem is to break the hard link between one or both screens. If the logo lives in an AssetBundle, then some amount of streaming needs to occur before you can get a reference to the Asset. If the logo lives in the binary (inside a Resources folder, for example), then the UI panel will need to have a weak reference to the logo Asset and be loaded via an API such as Resources.Load.
解决此问题的方法是断开一个或两个屏幕之间的硬链接。 如果徽标位于AssetBundle中,则在获得对Asset的引用之前需要进行一些流式传输。 如果徽标位于二进制文件中(例如,位于Resources文件夹内),则UI面板将需要对徽标Asset进行弱引用,并通过诸如 Resources.Load之类 的API进行加载 。
![](https://i-blog.csdnimg.cn/blog_migrate/13d218005ef54dec374ff330f053ae7d.png)
A string is used as a weak reference to the logo image. User scripting will need to use the string to load the image at runtime and assign it to the proper component.
字符串用作徽标图像的弱引用。 用户脚本将需要使用字符串在运行时加载图像并将其分配给适当的组件。
User scripting will need to use the string to load the image at runtime and assign it to the proper component.A happy middle ground may be to include the AssetBundle containing the logo Asset inside the application’s StreamingAssets directory. You will still load the Asset from the AssetBundle, but since you are hosting the bundle locally, you will not pay the cost in time required to download the content.
用户脚本将需要使用字符串在运行时加载图像并将其分配给适当的组件。 一个愉快的中间立场可能是在应用程序的 StreamingAssets目录中 包括包含徽标Asset的AssetBundle 。 您仍然可以从AssetBundle加载资产,但是由于您是在本地托管捆绑软件,因此您无需及时支付下载内容所需的费用。
It is not intuitive to use strings, paths or GUIDs to reference Assets, but you may want to create custom inspectors that enable Unity’s default drag-and-drop reference functionality on your weakly referenced fields. And don’t forget to use Unity’s MemoryProfiler package to identify Assets that are duplicated in Memory. Note that the Addressables system has its own mechanism for checking for duplicates in dependencies (for more information, see the documentation).
使用字符串,路径或GUID引用资产不是很直观,但是您可能需要创建 自定义检查器, 以在弱引用字段上 启用Unity的默认拖放引用功能 。 而且,请不要忘记使用Unity的 MemoryProfiler包 来标识在内存中重复的资产。 请注意,Addressables系统具有自己的机制来检查依赖项中的重复项(有关更多信息, 请参见文档 )。
结论 (Conclusion)
Even though the Addressables system provides an abstraction on top of AssetBundles, knowing how things work under the hood can help you avoid costly performance problems like the ones described in this article.
即使Addressables系统在AssetBundles之上提供了一个抽象,了解幕后的工作方式也可以帮助您避免代价高昂的性能问题,如 本文所述。
If you’re currently using Addressables we want to hear from you via this short survey.
如果您当前使用的是“可寻址对象”,我们希望通过这份简短的调查来听取您的意见。
We’re planning a roadmap for future entries of this series. Is there any area you’d like us to focus on? Leave a comment to let us know!
我们正在为本系列的未来作品规划一个路线图。 您想让我们关注什么领域? 发表评论让我们知道!
assetbundles