Skip to content

Performance Guide

Aprius edited this page Nov 4, 2024 · 7 revisions

For vs Foreach

Tip

Lists: for loop is generally faster.

Arrays: foreach loop can be as fast or sometimes faster than for.

1, Lists: In Unity, for is usually faster than foreach when iterating over List objects. This is because foreach creates an enumerator object, which can add a slight overhead, while for directly accesses the elements by index. This extra allocation in foreach can impact performance slightly, especially in scenarios where garbage collection (GC) overhead is a concern.

2, Arrays: For arrays, the foreach loop can sometimes be as fast as, or even faster than, a for loop. This is because the C# compiler optimizes foreach for arrays, making it nearly equivalent to a for loop. Since arrays are fixed-size and their elements are stored in a contiguous block of memory, the compiler can generate very efficient IL (Intermediate Language) code for foreach on arrays, often making it just as efficient as a for loop.

  • When to Prefer One Over the Other
    • Use for with Lists: For cases where you’re iterating over large lists or have performance-sensitive code, for is generally preferred for List. This can avoid the extra enumerator allocation that comes with foreach.
    • Use foreach with Arrays: If you are iterating over arrays, foreach is often just as performant as for, and it can make your code more readable.

IEnumerable<T>

Be careful with classes or methods that take IEnumerable as an argument (like System.Linq, or List's AddRange...) GC.Alloc is allocated here.

image

You can create extension methods that accept input arguments of specific data types instead of IEnumerable<T>

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static List<T> Adds<T>(this List<T> source, List<T> entries)
        {
            for (int i = 0; i < entries.Count; i++)
            {
                source.Add(entries[i]);
            }

            return source;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static List<T> Adds<T>(this List<T> source, T[] entries)
        {
            foreach (var e in entries)
            {
                source.Add(e);
            }

            return source;
        }

Check Null

Note

Unity has two memory spaces: native memory and managed memory. Resources loaded by the Unity engine are placed in native memory, and strings and binary data loaded on the C# side are placed in managed memory.

When you call GetComponent of a GameObject it will query the data in native memory and return the address of that component (this address is stored in managed memory). When this GameObject is destroyed the component's data in native memory will be deleted but the information about its address in the previous managed memory will not.

So you should assign null to unity object variables after using them.

var player = GetComponent<Player>();
// TO_DO
player = null;

That's why you should be careful when comparing Unity.Object to null

read more infomation here or here

Tip

In short we will try to use the null conditional operator even with objects that have been destroyed.

        /// <summary>
        /// m_MyGameObject is not truly null, but rather a sort of “null simulator” <br/>
        /// Then you can call: <br/>gameObject.OrNull()?.DoSomething();
        /// </summary>
        /// <param name="source"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T OrNull<T>(this T source) where T : Object { return source == null ? null : source; }

now you can use

        transform.OrNull()?.Translate(new Vector3(1, 0, 1));
Clone this wiki locally