Mastering C# and Unity3D

Loop Performance: Part 5 (New Compiler, IL2CPP)

Apr 10, 2017

Now that Unity has a new compiler that makes foreach loops not create garbage with List<T>, it’s time to re-test all the kinds of loops to see if anything’s changed. This article is the first in the series to test on a real Android device using IL2CPP, so these numbers should be much more accurate for most games. Read on for the results!

If you want to try out the test yourself, simply paste the above code into a TestScript.cs file in your Unity project’s Assets directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode, ideally with IL2CPP. I ran it that way on this machine:

LG Nexus 5X

Android 7.1.2

Unity 5.6.0f3, IL2CPP

And here are the results I got:

Size

Array For

Array While

Array Foreach

Array ForEach (Uncached)

Array ForEach (Cached)

List For

List While

List foreach

List Foreach (Uncached)

List ForEach (Cached)

10

5

4

4

51

25

11

11

28

49

27

100

35

34

34

179

225

96

96

239

202

252

1000

440

433

407

1767

2248

964

960

2359

1784

2667

The results are certainly different this time! With arrays, it doesn’t make any difference if you use for, foreach, or while. You’ll get the same speedy results with any of the three. If you use the ForEach extension method, you’ll suffer a 4-13x slowdown!

List<T> has different results. Good old for and while loops are still unquestionably the fastest, but foreach can’t keep up. Even though it’s not creating any garbage anymore, it takes about 2.5x longer to loop with foreach on a List<T>! Actually, foreach is on par with the List<T>.ForEach method when you use a cached delegate.

Compared to the previous article, it’s now easy to recommend for or while loops universally. It doesn’t matter if you’re using List<T> or a plain array, a few elements or a great many, you’ll always get the best performance with for or while. If you’re using a plain array, you can opt for foreach with no penalty, but make sure to not do this with List<T>. ForEach functions that take a delegate should never be used when performance is critical.