AssetBundle进阶内存优化(Unity 4.x)

简介:

测试环境(Unity 4.7 + NGUI)

在项目中,我们用NGUI制作了2个UI,分别是a.prefab 和b.prefab,它们都使用了一张名为c.png的贴图(这种现象在开发中非常常见,很多时候可能是数十个UI Prefab使用了同一张贴图)。我们使用依赖项打包,打包的结果分别是3个文件:
0.png

我们可以看到,在文件层面上已经没有冗余了,a.bundle及b.bundle都没有贴图的资源,贴图的资源都在c中。

按照常规的加载过程使用如下代码:

WWW wwwc = new WWW("file://c.bundle");
        yield return wwwc;
        wwwc.assetBundle.LoadAll();
        WWW wwwa = new WWW("file://a.bundle");
        yield return wwwa;
        WWW wwwb = new WWW("file://b.bundle");
        yield return wwwb;
        GameObject goa = GameObject.Instantiate(wwwa.assetBundle.mainAsset) as GameObject;
        GameObject gob = GameObject.Instantiate(wwwb.assetBundle.mainAsset) as GameObject;

这样的代码能成功加载出我们想要的资源,但这个时候如果我们去看Memory,就会发现冗余数据:
请输入图片描述

我们发现,c的纹理已经被加载出来了,并且已经占用了内存,但是c.bundle的文件映射依然还躺在内存中。一份数据出现了2份内存开销,这对于我们来说是不可饶恕的。按照Unity的要求如果要释放掉c.bundle的文件映射内存,需要调用AssetBundle.UnLoad(false),可是调用过这个函数之后对它有依赖的文件就没有办法再生成出来了,即你会发现纹理那个位置纹理指向的是null。比如这个时候还有其他的Prefab也使用了这张纹理,你会发现使用Bundle加载出来后材质指向的纹理为空,即使这个时候c的纹理已经在内存中。当然你还可以再次加载c.bundle,然后再加载其他Prefab,但你会发现内存中出现了两个叫c的纹理,这个更扯了,很明显不是一个合格的解决方法。

这个时候我们可以采用自我管理引用的方法来解决这个问题。这里以修改UIAtlas为例,同样的原理可以解决其他复杂引用的问题,比如UIFont,甚至3D场景的纹理管理等)。

首先我们调整UIAtlas的代码,在编辑器模式下存下UIAtlas的纹理及与材质的引用关系。这样我们在Bundle中就可以获得这个UIAtlas的纹理引用关系。

[SerializeField] public string[] propertiesName;    //材质中对应使用的纹理PropertyName
    [SerializeField] public string[] propertiesTextureName;     //纹理中的名字
public void MarkAsChanged ()
    {
#if UNITY_EDITOR
        NGUITools.SetDirty(gameObject);
        ReFlushTextureName();
    …..
#endif
}
public void ReFlushTextureName()
    {
        #if UNITY_EDITOR            
        if(material.shader)
        {
            List<string> pns = new List<string>();
            List<string> tns = new List<string>();
            for(int i = 0 ; i < ShaderUtil.GetPropertyCount(material.shader);i++)
            {
                if(ShaderUtil.GetPropertyType(material.shader,i) == ShaderUtil.ShaderPropertyType.TexEnv)
                {
                    string propertyname = ShaderUtil.GetPropertyName(material.shader,i);
                    Texture t = material.GetTexture(propertyname);
                    pns.Add(propertyname);
                    tns.Add(t.name);
                }
                
            }
            propertiesName = pns.ToArray();
            propertiesTextureName = tns.ToArray();
        }
        #endif
    }

正如代码所示,这个UIAtlas所使用的纹理信息已经被我们保存到 PropertiesName 和 PropertiesTextureName 这两个变量中。这些变量名将会被打包到Bundle中,并且在我们重新解开Bundle的时候可以得到。

其次,我们在c.bundle加载出来后,建立纹理名字对纹理的关系表,然后Unload(false)掉。

Texture2DBundlerCache 是一个简单的名字纹理的查找表,提供名字对纹理的添加、查找 、删除等功能,这里不再重复代码了,相信各位都能搞定。

最后我们再修改UIAtlas的代码,使得当材质在使用的时候,会重新将材质与纹理的引用关系恢复。是的,纹理已经在内存中了。

public Material spriteMaterial
    {
        get
        {
            if(material.mainTexture == null)
            {
                if(propertiesName != null)
                {
                    for(int i = 0;i < propertiesName.Length;i++)
                    {
                        material.SetTexture(propertiesName[i], Texture2DBundlerCache.Instance.Get(propertiesTextureName[i]) );
                    }
                }
            }
}
}

这样,我们就可以通过一个很小的表的开销及数个字符串的开销,来避免大量的文件内存占用,特别是在一些复杂引用关系中可以游刃有余地Unload掉资源,非常有效地控制住内存开销,而且由于是自己做的引用表,因而更加可控。





原文出处:侑虎科技
本文作者:admin
转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。

目录
相关文章
|
8月前
|
开发框架 Java .NET
《unity游戏优化》第8章内存优化
《unity游戏优化》第8章内存优化
|
存储 设计模式 缓存
Unity面试题——Unity性能优化
Unity面试题——Unity性能优化
327 0
|
XML 存储 人工智能
Unity面试题——Unity脚本基础
Unity面试题——Unity脚本基础
254 1
|
图形学 开发者
Unity初学者必备5款资源插件
Unity技术经理Sam Dogantimur为Unity初学者精心挑选和推荐了5款入门必备资源插件,涵盖游戏开发原型创作、着色器特效以及角色控制等,帮助Unity新手快速上手游戏开发。 我们将详细介绍这5款插件,获取插件请访问:https://shop135452397.taobao.com 视频介绍 Playmaker Playmaker是一款功能强大的可视化编程插件,被广泛应用于快速制作游戏原型,为游戏中的角色添加AI,制作过场动画等使用Playmaker不要求用户有任何编码知识,仅需要了解基本的逻辑思维,以及如何使用Unity的菜单和基本知识。
|
图形学 UED
Unity打包/读取AssetBundle资源全教程
Unity 资源AssetBundle打包 本文提供全流程,中文翻译。 Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) Chi...
2140 0
|
测试技术 Go 图形学
unity中实现简单对象池,附教程原理
Unity对象池的创建与使用 本文提供全流程,中文翻译。 Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) Chinar —— ...
2527 0
|
存储 缓存 API
AssetBundle基本介绍
翻译自官方文档: https://unity3d.com/cn/learn/tutorials/topics/best-practices/assetbundle-fundamentals 本章讨论AssetBundles。
1236 0