Unity资源加载速度研究

作者: carber | 来源:发表于2017-07-23 21:24 被阅读1503次

对于一款游戏来说,如果想要一个好的游戏体验需要一个稳定帧数。如果游戏跑60帧的话,那每帧只有16.67ms,但很多时候加载一个资源就花费了100ms甚至1000ms。这就是正常游戏中常见的卡顿问题,资源加载引起的卡顿带来很多的困扰,如何提高资源在速度是一个有意义的问题。由于不了解资源加载类背后的实现逻辑,这里通过实验来推测影响资源加载的因素。

下面分享一个简单的实验数据,来认识资源结构对加载速度的影响,首先看定义的数据类。

public class SingleData : MonoBehaviour {
    public int data;
    public string strData;
}
public class SingleDataArray : MonoBehaviour
{
    public List<int> data;
    public List<string> strData;
}

然后生成需要的数据,这里为了使结果对比明显设置对象数量为1W个。

第一个数据类型为多数据,单GameObject对象,一个GameObject挂载1W个mono。

static void MultData_OneObject()
{
    GameObject go = new GameObject("MultData-OneObject");
    GameObject child = new GameObject("ChildData");
    child.transform.parent = go.transform;
    for (int i = 0; i < MAX_COUNT; ++i)
    {
        SingleData data = child.AddComponent<SingleData>();
        data.data = i;
        data.strData = i.ToString();
    }

    PrefabUtility.CreatePrefab(PATH_ROOT + "MultData_OneObject.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
}

第二个数据类型为多数据,多GameObject对象,每个GameObject挂载1个mono。

static void MultData_MultObject()
{
    GameObject go = new GameObject("MultData-MultObject");
    GameObject child = new GameObject("ChildData");
    child.transform.parent = go.transform;
    for (int i = 0; i < MAX_COUNT; ++i)
    {
        GameObject subGo = new GameObject("subGo" + i);
        subGo.transform.parent = child.transform;
        SingleData data = subGo.AddComponent<SingleData>();
        data.data = i;
        data.strData = i.ToString();
    }

    PrefabUtility.CreatePrefab(PATH_ROOT + "MultData_MultObject.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
}

第三个数据类型为数据数组,单GameObject对象,数据数组参见SingleDataArray 定义。

static void DataArray_OneObject()
{
    GameObject go = new GameObject("DataArray-OneObject");
    GameObject child = new GameObject("ChildData");

    child.transform.parent = go.transform;
    SingleDataArray data = child.AddComponent<SingleDataArray>();
    data.data = new List<int>();
    data.strData = new List<string>();

    for (int i = 0; i < MAX_COUNT; ++i)
    {
        data.data.Add(i);
        data.strData.Add(i.ToString());
    }

    PrefabUtility.CreatePrefab(PATH_ROOT + "DataArray_OneObject.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
}

第四个数据类型为数据数组,多个GameObject对象,数组数据挂载在其中一个GameObject上。

static void DataArray_MultObject()
{
    GameObject go = new GameObject("DataArray-MultObject");
    GameObject child = new GameObject("ChildData");

    child.transform.parent = go.transform;
    SingleDataArray data = child.AddComponent<SingleDataArray>();
    data.data = new List<int>();
    data.strData = new List<string>();

    for (int i = 0; i < MAX_COUNT; ++i)
    {
        data.data.Add(i);
        data.strData.Add(i.ToString());

        GameObject subGo = new GameObject("subGo" + i);
        subGo.transform.parent = child.transform;
    }

    PrefabUtility.CreatePrefab(PATH_ROOT + "DataArray_MultObject.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
}

然后就是测试资源加载速度了,这四类数据数据内容相似有较大的对比意义。下面的测试数据验证了一些想法,但是结果还是和预想有较大的差异。

MultData_OneObject

TotalCount=10004,FileSize=1099KB,AssetBundleSize=392KB
PC Resources.Load 2058ms, Instantiate 1758ms
PC AssetBundle.LoadFromFile 3ms,AssetBundle.Load 2325ms,Instantiate=1797ms

MultData_MultObject

TotalCount=30004,FileSize=3677KB,AssetBundleSize=1276KB
PC Resources.Load 414ms, Instantiate 61ms
PC AssetBundle.LoadFromFile 10ms,AssetBundle.Load 1481ms,Instantiate=72ms

DataArray_OneObject

TotalCount=5,FileSize=122KB,AssetBundleSize=81KB
PC Resources.Load 0ms, Instantiate 2ms
PC AssetBundle.LoadFromFile 0ms,AssetBundle.Load 2ms,Instantiate=2ms

DataArray_MultObject

TotalCount=20005,FileSize=2732KB,AssetBundleSize=853KB
PC Resources.Load 262ms, Instantiate 25ms
PC AssetBundle.LoadFromFile 7ms,AssetBundle.Load 782ms,Instantiate=29ms

数据分析

数据比较多,也只是测试了在PC上执行的速度。由于资源是放在SSD上的所以在I/O不会出现性能问题,结果可以认为是CPU的开销。手机上由于I/O以及更弱的CPU加载速度回更慢,不过这里的数据对比已经非常有参考意义与价值了。

对比MultData_OneObject和MultData_MultObject可以发现单个GameObject挂载1W的mono对性能有极大的影响,而1W个GameObject每个各挂1个mono则有较好的表现。虽然在加载上依旧很慢,但是资源实例化(Instantiate)的提升是显著的。

接着对比MultData_MultObject和DataArray_MultObject可以发现,通过把mono的数据合并到一个对象,并以数组的方式存储也能对资源加载和资源实例化有一个较大的提升。

最后对比DataArray_MultObject和DataArray_OneObject可以发现,当把1W个无用的GameObject对象移除后的资源加载和资源实例化有一个极大的提升,即使同步加载这么多数据也不会出现什么问题了。

通过对比不同资源组织方式对性能的影响,我们清晰的认识到了一些对资源性能影响的关键性要素。对象数量极大的影响资源加载速度,在AssetBundle打包后更加明显。同时GameObject数量对资源加载速度的影响要大于mono对象对加载速度的影响。最后如果一个GameObject挂载过多的mono则会导致资源加载与资源实例化性能急剧降低。

更进一步

在了解对象数量对加载速度影响后,我们想通过把资源按数组的方式组织来提升资源加载速度。然而很多情况下这是很难达成的,也有诸多不方便的地方。

之后在Unity文档中发现了ScriptableObject能帮助我们减少对象数量提高加载速度,同时还能帮助我们节省内存。

ScriptableObject is a class that allows you to store large quantities of shared data independent from script instances. Do not confuse this class with the similarly named SerializableObject, which is an editor class and fills a different purpose. Consider for example that you have made a prefab with a script which has an array of a million integers. The array occupies 4MB of memory and is owned by the prefab. Each time you instantiate that prefab, you will get a copy of that array. If you created 10 game objects, then you would end up with 40MB of array data for the 10 instances.

ScriptableObject主要的作用是帮助减少重复对象,把数据直接以资源的形式保存以复用资源。当然比较好的做法是在制作的时候用mono保存数据,最后导出为文本数据。这样也能极大的提高资源加载速度。

不同的资源加载方式对资源加载速度也有较大差异,资源的形式也是多种多样的。通过对不同事物建立对应模型并测试,可以帮助认识事物、改善事物。最近比较忙没做资源加载方式对不同资源类型资源的影响,有兴趣的同学可以尝试下,相信会有很大的收获。

[完 2017-07-23 Carber]

相关文章

  • Unity资源加载速度研究

    对于一款游戏来说,如果想要一个好的游戏体验需要一个稳定帧数。如果游戏跑60帧的话,那每帧只有16.67ms,但很多...

  • Unity子包加载资源卡顿

    现象:Unity游戏母包加载资源启动速度正常,但是经过apktool工具重新生成的子包启动速度变慢变卡顿。 原因:...

  • Unity3D WWW用file协议下载失败问题

    Unity3D中加载本地或远程资源会用到WWW类,最使用Unity3D的WWW类加载本地磁盘资源时发现总是加载失败...

  • Unity AssetBundle 资源无法卸载,导致内存泄漏

    我们在使用Unity 使用AssetBundle加载资源时,在资源加载完成后不能调用 AssetBundle.un...

  • Unity3d常用两种加载资源方案:Resources.Load

    初步整理并且学习unity3d资源加载方法,预计用时两天完成入门学习Unity3d常用两种加载资源方案:Resou...

  • Unity 加载资源

    在Resources文件夹里面放入资源。加载如: 扩展方法-扩展系统组件ref 、out、params参数区别 r...

  • Unity资源加载

    资源加载 一、public 面板拖拽。大项目和多人项目基本都用不到。 二、Resources.load 商用不...

  • unity内存优化

    unity的内存优化主要集中在一下三块: www加载资源管理 美术资源管理 UI功能管理 www加载资源管理 原文...

  • Unity存储相关

    前言 我们在用Unity开发的过程中经常会遇到从本地加载资源以及保存资源到本地这样的需求,Unity也提供了集中本...

  • 加载unity资源问题

    1.loadfromfile/load assert()失败的解决 1.0确保路径正确 1.1使用file://协...

网友评论

    本文标题:Unity资源加载速度研究

    本文链接:https://www.haomeiwen.com/subject/fyzmkxtx.html