捆绑资源_资产捆绑与资源:内存摊牌

捆绑资源

Lately we’ve gotten a lot of inquiries about using Asset Bundles over the old school Resources system and why loading an Asset from the former has a higher memory overhead than the latter.

最近,我们有很多关于在旧版资源系统上使用Asset Bundles的问题,以及为什么从前者加载资产比后者具有更高的内存开销。

For those of you just looking for the TLDR: They don’t, or rather in the long run Asset Bundles will have a much lower memory overhead if you take advantage of what they can do that the Resources system cannot. If you are not familiar with Asset Bundles and want to learn more, you can refer to the Unity Manual and the Asset Bundles & Resources Guide.

对于那些只是在寻找TLDR的人:他们没有,或者从长远来看,如果利用资源系统无法做到的事情,资产捆绑将具有更低的内存开销。 如果您不熟悉资产捆绑包并且想了解更多信息,可以参考 Unity手册资产捆绑包和资源指南

Jumping right in, we received several bug reports all basically saying the same thing: When I load an Asset from an Asset Bundle I see my memory usage jump several megabytes but I do not see this jump when using Resources. In reproducing the steps of the bug we noticed very similar results: normal memory usage at the start, the memory jump when an Asset is loaded, and then noticed that the memory doesn’t return to the original value.

跳进去,我们收到了一些错误报告,基本上都说相同的话:从资产捆绑中加载资产时,我看到我的内存使用量跳了几兆字节,但是在使用资源时看不到这种跳升。 在重现该错误的步骤时,我们注意到了非常相似的结果:开始时正常使用内存,加载Asset时内存跳跃,然后注意到该内存未恢复为原始值。

资产捆绑的内存使用情况 (Memory usage for Asset Bundles)

Memory Usage for Asset Bundles

资源的内存使用情况 (Memory usage for Resources)

Memory usage for Resources

So, before we get into the actual numbers, let’s talk about the system that gives us those numbers and how they relate to each other. Unity’s native memory system uses several fixed-size block allocators that vary in size from 1 MB to 32 MB (avg. 1 MB to 4 MB) depending on what type of work they are assigned to do, such as main thread vs. background thread, or what’s the current running platform. The Reserved Total is the sum of all blocks allocated by the OS, while Used Total is what is actively being used by Unity out of the Reserved Total. Each of the area labels, FMOD, Profiler, etc. represent a set of those allocators or estimated external memory reported by the system. You can read about the area labels on our Memory Profiler manual page. There are a few things to note that are not on the manual page: Used and Reserved totals do not include FMOD values at the time of writing this blog post (Unity 5.5.0f3). We have a fix for this on it’s way. Total System Memory Usage is the system reported virtual memory size by the platform, which is not a feature of all platforms and 0 is displayed in those cases. Finally, Used Total does not take into account an object’s header or byte alignment, however Reserved Total does. So for looking at memory usage of Asset Bundles vs. Resources, we will focus on both the Used Total and Reserved Total sections for the Unity area label.

因此,在讨论实际数字之前,让我们先讨论为我们提供这些数字的系统以及它们之间的关系。 Unity的本机内存系统使用几个 固定大小的块分配器 ,其大小从1 MB到32 MB(平均1 MB到4 MB)不等,具体取决于分配给他们执行的工作类型,例如主线程与后台线程,或当前运行的平台是什么。 预留总数是操作系统分配的所有块的总和,而已用总数是Unity在 预留总数中 正在积极使用的东西 。 每个区域标签FMOD,Profiler等都代表一组由系统报告的分配器或估计的外部存储器。 您可以在我们的 Memory Profiler 手册页 上阅读有关区域标签的信息 。 手册页上没有要注意的几件事:在撰写此博客文章时(Unity 5.5.0f3),使用和保留总计不包括FMOD值。 我们已经对此进行了修复。 系统内存总使用量是 平台 报告的系统 虚拟内存 大小,这不是所有平台的功能,在这些情况下显示为0。 最后,Used Total 不考虑对象的 标头或字节对齐 ,但是Reserved Total则考虑。 因此,为了查看资产捆绑与资源的内存使用情况,我们将重点关注 Unity区域标签 的“已用 总计”和“预留总计”部分。

Another piece of information that is necessary to understand what is going on in the profiler, is how Asset Bundle and Resources data is laid out on disk. Both Resources and Asset Bundles under the hood are very similar in data structures, in that they both have a single file that contains the serialized data for every object, additional resource files for efficient async loading(textures, audio, etc), and a map of Asset file path to serialized objects to load when requested. Asset Bundles pack those files together in an archive and the map is stored in the serialized data in an Asset Bundle object. Resources stores it’s map in a global singleton called the ResourceManager and the files themselves are just lose on disk. Additionally, unlike the Resources system, Assets don’t have to all be in the same Asset Bundle making it possible to load only a subset of data to control memory usage to a greater degree. More details about Asset Bundle internal structure can be found in the related Unity manual page.

要了解事件探查器中正在发生的事情,另一条必需的信息是如何在磁盘上布置资产捆绑和资源数据。 底层的资源包和资产包在数据结构上非常相似,因为它们都有一个文件,其中包含每个对象的序列化数据,用于高效异步加载的其他资源文件(纹理,音频等)和映射请求时要加载的序列化对象的Asset文件路径的数量。 资产捆绑包将这些文件打包到一个归档文件中,并且映射存储在资产捆绑包对象的序列化数据中。 资源将其地图存储在名为ResourceManager的全局单例中,文件本身只是丢失在磁盘上。 此外,与资源系统不同,资产不必全部位于同一个资产束中,从而可以仅加载一部分数据来更大程度地控制内存使用。 有关Asset Bundle内部结构的更多详细信息,请参见相关的 Unity手册页

资产捆绑 (Asset Bundles)

Asset Bundles

资源资源 (Resources)

Resources

Using our knowledge of the memory and file systems of Unity, we can now talk in detail about what we are seeing with the memory usage values. The first thing that stands out is that the Reserved Unity area for Asset Bundles grew 10 MB, while for Resources this did not grow at all. Why is that? This is actually due to the block allocators mentioned earlier. For this particular memory usage test we used the AsyncBundleLoader.cs behavior which uses Coroutines with Async loading APIs. This is important to note because this combination actually uses different block allocators that, up until this point, have yet to be used. So this 10 MB jump is 2 allocators, allocating their initial blocks of memory, and 1 allocator that needs more memory for the new objects, so it allocates a 4 MB block. Of the 2 new allocators, one is allocating a 2 MB block for Asset Bundle Async loading, the other is allocating a 4 MB block for Type Trees (more on Type Trees later). These blocks sizes are optimized for loading multiple Assets and bundles in parallel. For example, you should be able to load objects from 4 to 5 Asset Bundles at the same time without the the allocators for Asset Bundle Async loading or Type Trees needing new blocks. This of course depends on the Asset Bundle size and compression use, as well as how many unique script types you have in these bundles.

使用我们对Unity内存和文件系统的了解,我们现在可以详细讨论关于内存使用率值的信息。 突出的第一件事是, 资产捆绑包 的 预留Unity 区域增长了10 MB,而资源资源却没有增长。 这是为什么? 这实际上是由于前面提到的块分配器。 对于此特定的内存使用情况测试,我们使用了 AsyncBundleLoader.cs 行为, 该 行为将协程与Async加载API结合使用。 注意这一点很重要,因为这种组合实际上使用了不同的块分配器,直到这一点为止,还没有使用过。 因此,这10 MB的跳跃是2个分配器,分配它们的初始内存块,以及1个分配器,这些分配器需要更多的内存用于新对象,因此它分配了4 MB的块。 在这2个新的分配器中,一个分配一个2 MB的块用于Asset Bundle Async加载,另一个分配一个4 MB的块用于类型树(稍后在类型树上更多)。 这些块大小经过优化,可并行加载多个资产和捆绑包。 例如,您应该能够同时加载4到5个资产束中的对象,而无需资产束异步加载或类型树的分配器需要新的块。 当然,这取决于资产捆绑包的大小和压缩使用情况,以及这些捆绑包中有多少种独特的脚本类型。

Of those allocation blocks, the 4 MB block for Type Trees is only needed when actively loading objects from Asset Bundles. This block should go away after you are done, however because of how we structured our Coroutine in the example, the AssetBundleRequest object is not being cleaned up by the garbage collector as it’s still in scope. As for the 2 MB block for Asset Bundle Async loading, this is used for threaded read buffers into the Asset Bundle archive, and will go away when there are no more internal references to the bundles. The final 4 MB block will not go away as that block is on the main allocator that is used for all our object storage. Since in a typical project object creation / deletion happens very frequently, we pool memory for reuse instead of releasing it back to the allocator. When you look at the final unloaded Reserved Unity values, you will notice the Asset Bundle case (64.1 MB) is very close to the Resources case (63.3 MB), only due to the order that the allocators obtained new blocks.

在这些分配块中,仅当从资产捆绑包中主动加载对象时才需要4 MB的类型树块。 完成后,该块应该消失了,但是由于示例中我们构造Coroutine的方式,AssetBundleRequest对象没有被垃圾收集器清理,因为它仍然在作用域内。 至于用于资源捆绑包异步加载的2 MB块,这用于线程化读取缓冲区到资产捆绑包归档中,并且在没有更多内部引用时将消失。 最后的4 MB块不会消失,因为该块位于用于所有对象存储的主分配器上。 由于在典型的项目中,对象的创建/删除非常频繁,因此我们将内存池化以供重用,而不是将其释放回分配器。 当查看最终卸载的保留Unity值时,您会发现Asset Bundle情况(64.1 MB)非常接近Resources情况(63.3 MB),这仅是由于分配器获得新块的顺序所致。

So we’ve spent all this time talking about Reserved memory, what about the actual efficiency of using that Reserved memory between Asset Bundles and Resources? This one is actually really easy as this is what the Used Unity area is directly showing us. In the Asset Bundle case, it’s using 21.7 MB of its Reserved memory while Resources is using slightly more, at 22.2 MB. In addition, when we unload, this memory drops to 20.7 MB and 21.2 MB respectively. So Asset Bundles is the clear winner for efficiently utilizing memory. As you may have noticed, Asset Bundle usage after unloading is significantly larger (4.4 MB) than when it started. This is due to memory being pooled for reuse as mentioned previously, so if you reload that Asset Bundle and Asset, it returns right back to the 21.7 MB. In the Resources case, the memory difference between start and unload is due to rounding errors.

因此,我们花了所有时间讨论预留内存,在资产束和资源之间使用该预留内存的实际效率如何? 这实际上非常容易,因为这是Used Unity区域直接向我们显示的内容。 在Asset Bundle的情况下,它使用21.7 MB的预留内存,而Resources使用的则略多一点,为22.2 MB。 此外,当我们卸载时,该内存分别降至20.7 MB和21.2 MB。 因此,Asset Bundles是有效利用内存的明显赢家。 您可能已经注意到,卸载后Asset Bundle的使用比开始时大得多(4.4 MB)。 这是因为如前所述,内存已被池化以供重用,因此,如果您重新加载该资产捆绑包和资产,它将立即返回到21.7 MB。 在资源的情况下,启动和卸载之间的内存差异是由于舍入错误引起的。

The block allocations for Asset Bundles can be reduced, with tradeoffs in performance and backwards compatibility. As mentioned above, a 4 MB block allocation is unavoidable as there just is not enough memory available to load the object. Of the remaining 6 MB, 2 MB is due to using the Async loading APIs. So to avoid that block allocation, you just use the synchronous APIs at the cost of an FPS hitch. The final 4 MB allocation is due to the Type Tree system, and as mentioned above we would go into more detail. This system stores extra data in Asset Bundles, but not in Resources, that is used to make Asset Bundles compatible with a wider range of Unity versions and makes serialization attributes such as FormerlySerializedAs work. This allows you to continue using the same Asset Bundles if you upgrade to a newer version of Unity, or make minor code changes, instead of needing to rebuild them, and in return, make your users redownload entire asset bundles when your game changes. To disable writing this extra data, you pass in the BuildAssetBundleOptions.DisableWriteTypeTree option into the BuildPipeline.BuildAssetBundles API.

通过权衡性能和向后兼容性,可以减少资产束的块分配。 如上所述,不可避免的是要分配4 MB的块,因为没有足够的内存来加载对象。 在剩余的6 MB中,有2 MB是由于使用了异步加载API。 因此,为避免块分配,您只需使用同步API,而要付出FPS障碍。 最终的4 MB分配归因于类型树系统,如上所述,我们将进行更详细的介绍。 该系统将其他数据存储在Asset Bundles中,但不存储在Resources中,这些数据用于使Asset Bundle与更广泛的Unity版本兼容,并使诸如 FormerlySerializedAs之类的 序列化属性 起作用。 这样,如果您升级到新版本的Unity或进行较小的代码更改,就可以继续使用相同的资产捆绑包,而无需重建它们,而作为回报,当您更改游戏时,让用户重新下载整个资产捆绑包。 要禁用写入这些额外数据的功能,您可以将 BuildAssetBundleOptions.DisableWriteTypeTree 选项 传递 给 BuildPipeline.BuildAssetBundles API。

没有类型树的资源包同步加载 (Asset Bundles Loaded Synchronous without Type Trees)

Asset Bundles loaded synchronous without type trees

There you have it, Asset Bundles 1, Resources 0. If you want to reproduce this data yourself, the scripts used in this blog have been uploaded to a Github Gist. It’s currently setup to create 100 of each: Textures, Monobehaviors, and Prefabs and uses a fixed randomization seed, so on your machine it will generate the same output each time you run it (but probably different than mine). Just make sure your Asset Bundle project doesn’t accidentally contain a Resources folder with content, otherwise your memory values will be double what you would expect. Check it out, especially with 300 or even 500 of each.

在那里,资产捆绑包1,资源0。如果您想自己重现此数据,则此博客中使用的脚本已上载到 Github Gist 。 当前已设置为创建100个纹理,单色行为和预制,并使用固定的随机种子,因此在您的计算机上,每次运行它都会生成相同的输出(但可能与我的不同)。 只要确保您的Asset Bundle项目中不会意外包含包含内容的Resources文件夹,否则您的内存值将是您期望的两倍。 检查一下,尤其是每个检查300甚至500。

翻译自: https://blogs.unity3d.com/2017/04/12/asset-bundles-vs-resources-a-memory-showdown/

捆绑资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值