StackOverflowException во вложенном l oop в Unity c# - PullRequest
0 голосов
/ 13 января 2020

В Unity c# я получаю данные от json и нахожу / сравниваю игровой объект, используя вложенный l oop (как следующий код), чтобы установить эти данные в локальных игровых объектах. Но я получаю ошибку StackOverflowException после получения определенного количества объектов (что-то> 275). В основном, 80 раз l oop работает 10 раз, что выполняется 300 раз, см. Код ниже. (Примечание: этот код работает нормально при меньших числах, например, когда j <275). </p>

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();
        }
    }

1 Ответ

4 голосов
/ 13 января 2020

Ваш внутренний блок выполняется примерно в 300 * 10 * 80 = 240000 раз рекурсивно, хранит некоторые значения несколько раз и дополнительно требует более длительного анализа, чтобы понять, что там делается.

На самом деле я не вижу места, где вы изменил бы ObjList.objects в вашем методе .. так что говорит против простого использования закрытого l oop без какой-либо рекурсии и полей индекса "magi c":

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
                }
            }                
        }
    }
}

Переменные, которые вы сохраняете, простые типы, такие как int, string и ссылка Component. Ничего слишком сложного, с чем G C должен иметь дело.

На самом деле, на мой взгляд, это было бы еще лучше решить, если не использовать индексы для j и m вообще

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 очень дорог, поэтому, если это возможно, следует заранее сохранить ссылки. * 1 022 *

Например, указав тип floorStats непосредственно как StatesCalc[] и тип floorObjs a ObjectManager[], при условии, что вы ссылаетесь на них через инспектор, он автоматически сохранит соответствующую ссылку на тип, поэтому GetComponent требуется во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...