繁体   English   中英

Unity c#中嵌套循环中的StackOverflowException

[英]StackOverflowException in nested loop in Unity c#

在 Unity c# 中,我从 json 获取数据,我正在使用嵌套循环(如下代码)查找/比较游戏对象以在本地游戏对象中设置该数据。 但是在获得一定数量的对象(> 275)后,我收到了 StackOverflowException 错误。 基本上 80 次循环运行 10 次,运行 300 次,请参见下面的代码。(注意:此代码在较低的数字下运行正常,例如当 j < 275 时)。

public void SetDataInObject()
    {
        if (j < ObjList.objects.Count)  //count is approx 300
        {
            for (int k = 0; k < allObjs.Length; k++)  // Length is 10
            {                
                stCalc = uiMana.floorStats[k].GetComponent<StatesCalc>();

                for (int m = 0; m < allObjs[k].floorObjs.Length; m++)  //Length is 80
                {
                    string serverObj = ObjList.objects[j].name;
                    string localObj = allObjs[k].floorObjs[m].gameObject.name;

                    if (localObj == serverObj)
                    {
                        ObjManager curObjManger = allObjs[k].floorObjs[m].GetComponent<ObjManager>();
                        //Logic to set data in local objects
                    }
                }                
            }
            j++;
            SetDataInObject();
        }
    }

你的内部块运行大约300 * 10 * 80 = 240000次递归,多次存储一些值,另外需要一些更长的解析以了解那里做了什么。

实际上,我没有看到您可以在方法中更改ObjList.objects任何地方。

public void SetDataInObjects()
{
    for (var j = 0; j < ObjList.objects.Count; j++)
    {
        // This actually stays the same for all inner iterations until j is changed
        // so keep it around as long as possible to save resources
        var serverObj = ObjList.objects[j].name;

        for (int k = 0; k < allObjs.Length; k++)  // Length is 10
        {                
            stCalc = uiMana.floorStats[k].GetComponent<StatesCalc>();
            // Also this stays the same until k is changed
            // so keep the reference around to save access calls
            var currentObj = allObjs[k];

            for (int m = 0; m < currentObj.floorObjs.Length; m++)  //Length is 80
            {
                var localObj = currentObj.floorObjs[m].gameObject.name;

                if (localObj == serverObj)
                {
                    ObjManager curObjManger = allObjs[k].floorObjs[m].GetComponent<ObjManager>();
                    //Logic to set data in local objects
                }
            }                
        }
    }
}

您存储的变量是简单的类型,如intstringComponent引用.. GC 不应该关心什么太复杂。

实际上,在我看来,完全不使用jm索引会更好地解决这个问题

public void SetDataInObjects()
{
    foreach(var serverObj in ObjList.objects)
    {
        var serverName = serverObj.name;

        for (int k = 0; k < allObjs.Length; k++)  // Length is 10
        {                
            stCalc = uiMana.floorStats[k].GetComponent<StatesCalc>();
            // Also this stays the same until k is changed
            // so keep the reference around to save access calls
            var currentObj = allObjs[k];

            foreach (var floorObj in currentObj.floorObjs)  //Length is 80
            {
                if (localObjName.Equals(serverName))
                {
                    var curObjManger = floorObj.GetComponent<ObjManager>();
                    //Logic to set data in local objects
                }
            }                
        }
    }
}

这显然仍会运行内部块300 * 10 * 80 = 240000次,但使用在每次迭代后清除的局部变量,因此它们不会增加分配内存。

请注意,仍然重复调用GetComponent是非常昂贵的,如果可能的话,您应该事先存储引用。

例如,通过将floorStats的类型直接设置为StatesCalc[]并将StatesCalc[]的类型floorObjsObjectManager[] ,假设您通过 Inspector 引用这些,它将自动存储相应的类型引用,因此在运行时不需要GetComponent

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM