http://blog.csdn.net/lodypig/article/details/51879702

AssetBundle内存占用

  先上图,Don’t panic。 
Unity5-ABSystem(五):AssetBundle内存-LMLPHP
  我们从AssetBundle中加载资源一般会经过三个步骤:

  1. www、LoadFromFile、LoadFromMemory等接口加载AssetBundle本身。
  2. 通过AssetBundle.LoadAsset()等接口从AssetBundle中加载资源。
  3. 对于GameObject类资源,还需通过GameObject.Instantiate()创建clone。

  这几个步骤,都会产生内存分配,并且分别对应了图中不同颜色的部分。而图的左边已经写出了产生内存分配的接口,右边则标明了释放内存的方法。 
  接下来详细看看每部分的含义。 
    

  • 黑色部分:www类本身占用内存,通过www接口加载AssetBundle才会有这部分内存,www对象保留了一份对WebStream数据(粉色部分)的引用。使用www =null 或者 www.dispose()释放。其中www.dispose()会立即释放,而www = null会等待垃圾回收。释放www后WebStream的引用计数会相应减一。

  • 橙色部分:官方称为WebStream数据,是数据真正的存储区域。当AssetBundle被加载进来后,这部分内存就被分配了。它包含3个内容:压缩后的AssetBundle本身、解压后的资源以及一个解压缓冲区(图绿)。无论www(黑色部分)还是后面会提到的AssetBundle对象(粉色部分),都只是有一个结构指向了WebStream数据,从而能对外部提供操作真正资源数据的方法。而当www对象和AssetBundle对象释放时,WebStream数据的引用计数也会相应减1。当WebStream数据引用计数为0时,系统会自动释放。但为了不频繁地开辟和销毁解压Buffer,其中绿色Decompression解压缓冲区Unity会至少保留一份。例如同时加载3个AssetBundle时,系统会生成3个Decompression Buffer,当解压完成后,系统会销毁两个。

  • 粉色部分:AssetBundle对象,引用了橙色WebStream数据部分,并提供了从WebStream数据中加载资源的接口。通过AssetBundle.Unload(bool unloadAllLoadedObjects)释放。如果调用AssetBundle.Unload(false),将释放AssetBundle对象本身,其对WebStream引用也将减少,从而可能引起WebStream释放,我们也就无法再通过接口或依赖关系从该AssetBundle加载资源。但已加载的资源还可以正常使用。如果调用的是AssetBundle.Unload(true),不仅会释放WebStream部分,所有被加载出来的资源将被释放。无论true或false,AssetBundle.Unload()都将销毁AssetBundle,销毁后调用该AssetBundle对象的任何方法都不会生效或产生报错,也就是说这个接口只能被调用一次,不能先调用unload(false)再调用unload(true)。

  • 红色部分:上图中红色部分不是非常清楚,我们换一张图: 
    Unity5-ABSystem(五):AssetBundle内存-LMLPHP 
      这里紫色区域”AssetBundle文件内存镜像”就是上面的WebStream和www(黑橙)部分,虚线里的资源就是从AssetBundle加载出来的原始资源了,也属于WebStream范围,我们不再讨论。 
      而绿色实线内的资源(对应第一张图红色部分),也就是就是我们通过Instantiate()创建的GameObject所包含的资源。这些包含的资源又根据类型,与AssetBundle原始资源(WebStream资源部分)有不同的关系。有些如Texture、shader资源,我们通常只是使用,并不会对其做出改动,所以仅仅是引用关系;而每个GameObject都是特殊的,所以是完全复制了一份;至于Mesh和Material,则是引用+复制的关系。

建议


实测

  以上图片和解释来自于官方资料总结,但从加载接口可以看到是Unity5.3之前的版本,而在Unity5.3.4中是否真的如上面所言,我们仍需要“眼见为实”。毕竟没有亲测都是不可信的。 
  测试使用window平台,CPU i5-4750 3.2GHZ。从StreamingAsset下加载,测试时内存存在0.1M波动,但多次测试结果非常稳定。而加载耗时波动较大,不过不影响结论。 
  测试过程为:启动空的场景,先加载AssetBundle,再调用LoadAllAssets加载全部资源。在这个过程中,通过profile查看内存。 
  测试包含不压缩、LZMA压缩、LZ4压缩三种格式,压缩相关在Unity5-ABSystem(一):AssetBundle原理中有解释。 
  备注:unload(false)和unload(true)在一次测试中不能同时调用,所以其实是两次测试结果。由于表格显示关系,不要理解成unload(false)一次内存下降,unload(true)一次内存下降。例如下表第一行,调用前是203.3M,调用unload(true)直接降到37.4M,下降165.9M,但表格上标记(-82.1),仅仅是因为不想建立两个表格。

www加载实测

  使用www方式异步加载结果如下:


压缩
81.3M37.4M121.4M(+84)203.3M(+81.9)203.3M(+0)119.5M(-83.8)37.4M(-82.1)99ms66ms
LZMA44.9M37.4M117.3M(+79.9)199.2M(+81.9)199.2M(+0)1195M(-79.7)37.4M(-82.1)3377ms119ms
LZ471.8M37.4M111.6(+74.2)193.5M(+81.9)193.5M(+0)119.4M(-74.1)37.4(-82)99.7ms176ms

LoadFromFile加载实测

  使用LoadFromFile和LoadFromFileAsync接口加载,除了异步时间以外,其余差异不大,以LoadFromFile为例,测试结果如下。


压缩
81.3M38.5M38.5M(+0)120.5M(+82)120.5M(+0)38.5M(-82)1.3ms70.7ms
LZMA44.9M38.5M118.5M(+80)200.4M(+81.9)120.5M(-79.9)38.5M(-82)3312ms116ms
LZ471.8M38.5M38.5(+0)120.5M(+82)120.5M(+0)38.5(-82)1.2ms179ms

建议

    • 无论使用何种方式压缩AssetBundle,均使用AssetBundle.LoadFromFile和AssetBundle.LoadFromFileAsync接口加载AssetBundle。避免使用www加载。
    • 避免使用LZMA压缩,有较长的解压时间和两倍实际资源的内存占用,尽量使用LZ4压缩(需要升级5.3或更高)。
    • 如果使用LZ4或不压缩包体过大,可以自己再对AssetBundle进行压缩,首次进入游戏时解压。
05-23 03:12