Crave For Games

The text below is one of the notes from the StoneDrop development log. If you want a list of only technical articles you can go to the Articles page.
Unity performance optimizations for mobiles

Key points from a Unite talk about performance optimizations for mobile games in Unity.

Video 1. Optimizing Mobile Applications. June 2016, Unite Europe

Profiling tools:

- iOS: Instruments

- Android: VTune, Snapdragon Profiler

- UnityEditor: Profiler, Timeline, Memory Profiler.



- free iOS profiler included with XCode

- works with IL2CPP, profiles Unity native code too

- best tool for CPU profiling and startup time profiling

- how to start:[1]

- (some examples of where a typical workload may be situated in a callstack).


5.3+ Memory Profiler:

- free, available at:[2]

- only works in IL2CPP builds

- allows to get memory snapshot and track down the objects which are referencing resources

- helps to identify problem when the same resources from AssetBundles are loaded into memory multiple times and have same content but different instance ids.


Tips for memory usage:

- restrict RenderTextures for effects in size on mobile devices (iPad with retina uses 4k full-screen texture, consider half-res)

- wrap resource management into your own system to track which asset bundles are already loaded

- make your asset importer to ensure all assets are properly (auto) compressed and organized

- there is a mip-map mode in game view in the editor which shows whether the texture is too high for an object or too low

- Read/Write enabling on textures will double the memory size the texture takes at runtime

- Read/Write enabling ("on" by default) on meshes will also double the memory size (but "on" is required for mesh collider generation)

- disable Rig on non-animated models to prevent from Animator being instantiated at runtime

- enable mesh compression

- if you instantiate meshes in runtime - keep in mind the default MeshRenderer will be instantiated with "Cast/receive shadows - on", "Reflection probes - on", "Motion vectors - on". And if you are not using shadows, then this single MeshRenderer may enable the shadow pass before regular rendering

- audio is compressed at build time; use MP3 for iOS (supported and optimized) and Vorbis for Android; consider "Force Modo" for mobiles

- Mono heap never shrinks - only expand, so don't forget to trigger GC.Collect() after long operations with non-responsive UI (loading screens, scene switches)

- reuse your collections to avoid allocations, avoid boxing and strings

- closures and anonymous methods are sources of memory allocations (they are not displayed in profiler yet)

- default Dictionaries (and HashSets) use general implementation of Comparer, so if keys are value type - each operation will cause boxing of a value type (to pass it to the Comparer) and instantiation of the Comparer itself; the solution is to implement your own comparer which works with your value types w/o converting them to objects and pass it to Dictionary's constructor

- don't use foreach

- some Unity API returns arrays - just don't call those methods too often and sometime there is a way to avoid allocations at all by using other API methods

- be aware of params arguments because they are allocating array with each call.


Tips for Start-up time:

- forget about json or xml representation of your data in production code: parsers are too slow (and some of them are even based on Reflection); if you need - use builtin JsonUtility class which is based on internal serialization system and pretty fast

- use binary serialization

- split parsing into multiple frames or use threads for deserialization

- cache previous deserialization results

- parse only what you need (parts of files or split data into many small files)

- the more files in your "Resources" folder - the longer will Unity load it's index on app startup (for thousands of files it's already a noticeable time); consider moving majority of them to AssetBundles and load them on demand.


Tips for runtime:

- use Animator and Shader property ids (it's safe to call Shader.PropertyToID() or Animator.StringToHash() in static constructors or initializers of static classes)

- Unity doesn't have a generational garbage collector like in Mono or .Net, all the reference-type objects are stored in a simple heap, so if there are a lot of boxed objects - the GC have to scan through all of them each Collect() (a lot of CPU time)

- don't use regular expressions - they generate an enormous garbage and very slow (it's not a Java runtime here!)

- use StringComparison.Ordinal for all string comparisons to compare string bytes values - otherwise you can create locale-dependent bugs because of string coercion (which is also slow)

- String.StartsWith() and String.EndsWith() are 10-100x slower than a hand-coded byte-wise comparisons

- any method call (even property getter or setter) is an additional CPU time waste (also that's why List<> accessor is slower than array accessor)

- virtual or interface methods will never be inlined (even in IL2CPP), the same stands for property getters/setters (that's why is slower than new Vector(0,0,0)).


Link 1:

Link 2:

This article in social networks: