Unity code optimization memory management optimization

The project encountered a lag. I carefully checked the code and found no errors.

I carefully summarized the things that can be optimized
and recorded the problems that caused the lag.

1 coroutine

Before the project, everything about countdowns and the like was written using a coroutine.
Although the coroutine consumes very little threads, it still consumes extra money. Moreover,
many operations that use Ctrip to detect and destroy prefabs are also placed in the Update method. It's solved inside
. Solution: Put it in the Update method to execute it. If the coroutine can be used, don't use it.

Also: The yield of coroutines generally uses this yield return new WaitForSeConds(1f);
if many coroutines use new WaitForSeConds(1f);
then just turn it into a variable for everyone to share. This way, there is no need to do it every time. There is a new one.
Anyway, as long as there is new, there will be additional occupation. This is an easily overlooked place.

2 string

Analysis found on Baidu:

In C#, string is a reference type variable rather than a value type variable, even though it looks like it stores the value of the string. This means that strings will cause a certain amount of memory garbage.
Since strings are often used in code, we need to be extra careful about them.
Strings in C# are immutable, which means that their internal values ​​cannot be changed after they are created. Every time you perform an operation on a string (such as using the
"add" operation of a string), Unity will create a new string to store the new string, causing the old string to be discarded, so that Causing memory garbage.
We can use some of the following methods to minimize the impact of strings:

Reduce the creation of unnecessary strings. If a string is used multiple times, we can create and cache the string.
Reduce unnecessary string operations. For example, if there is a part of the string in the Text component that needs to change frequently, but other parts do not, we can divide it into two parts of the component, and set the constant part It can be similar to a constant string, such as the example below.

If we need to create strings in real time, we can use StringBuilderClass instead. StringBuilder is designed not to require memory allocation, thereby reducing the memory garbage generated by strings. Remove the code of the Debug.Log() function in the game. Although the function may output a null, the call to the function will still be executed, and the function will create a string of at least one character (null character). If there are a large number of calls to this function in the game, this will cause an increase in memory garbage.
In the following code, a string operation will be performed in the Update function. Such an operation will cause unnecessary memory garbage.

Normal writing is like this (there is a problem in terms of memory)

public Text tx_time; 
float timer; 
void Update() {
    
     
	timer += Time.deltaTime; 
	tx_time.text = "Time:" + timer.ToString(); 
}

Solution: Divide one Text into two Texts and splice
them together. If you write it this way, the memory will not increase, but the code looks so stupid! Stupid! Stupid!
Although we know that writing memory this way is optimal, we still don’t use it. Let’s record it first.

public Text tx_str; 
public Text tx_time; 
float timer; 
void Start() {
    
     
	tx_str.text = "Time:"; 
} 
void Update() {
    
    
	tx_time.text = timer.ToString() 
}

3 GameObject Tag optimization

For example, collision methods sometimes require tags to determine and perform some operations.

void OnTriggerEnter2D(Collider2D other)
{
    
     
	if (other.tag == "tag")
            {
    
    
                //操作
            }
}

Using gameObject.tag directly will generate memory garbage
. Solution:

Use gameObject.CompareTag()

if (other.gameObject.CompareTag(“tag”))
{
    
     
}

4 Creation and destruction of prefabs

Create
GameObject obj = Instantiate(prefab);
DestroyDestroy
( gameObject );

This is no problem, but if many prefabs are frequently created and consumed, it will be a problem. So
we made a thread pool for optimization, and used hiding to replace the destruction operation when it was time to destroy it.

 public class ObjectPool
    {
    
    
        private static ObjectPool instance;
        private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();
        private GameObject pool;
        public static ObjectPool Instance
        {
    
    
            get
            {
    
    
                if (instance == null)
                {
    
    
                    instance = new ObjectPool();
                }
                return instance;
            }
        }
        public GameObject GetObject(GameObject prefab)
        {
    
    
            GameObject _object;

            if (pool == null) //当场景没有对象池时(第一次进入游戏或者切换了场景),新建一个对象池游戏物品并清空字典
            {
    
    
                pool = new GameObject("ObjectPool");
                objectPool = new Dictionary<string, Queue<GameObject>>();
            }

            if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0)
            {
    
    
                _object = GameObject.Instantiate(prefab);

                PushObject(_object);

                GameObject childPool = GameObject.Find(prefab.name + "Pool");
                if (!childPool)
                {
    
    
                    childPool = new GameObject(prefab.name + "Pool");
                    childPool.transform.SetParent(pool.transform);
                }

                _object.transform.SetParent(childPool.transform);
            }

            _object = objectPool[prefab.name].Dequeue();
            _object.SetActive(true);
            return _object;

        }
        public void PushObject(GameObject prefab)
        {
    
    
            string _name = prefab.name.Replace("(Clone)", string.Empty);

            prefab.name = _name ;

            if (!objectPool.ContainsKey(_name))
                objectPool.Add(_name, new Queue<GameObject>());

            objectPool[_name].Enqueue(prefab);
            prefab.SetActive(false);

        } 
    }

In this way, prefabs can be reused without frequent creation and destruction. This optimization has a great impact on the project.

5 Garbage collection performs GC operations regularly

Actively calling GC operations When it does not affect the game experience (scene switching, etc.), we can actively call GC operations:

System.GC.Collect()

The above is a summary of some optimization areas. Please give me some advice. Thank you.
March 08, 2023 19:06:04

Guess you like

Origin blog.csdn.net/qq_32065601/article/details/129409431