Key points from a Unite talk about content optimization techniques for Unity.
Video 1. Let's Talk (Content) Optimization. November 2016, Unite
- instantiation is a serialization, memory buffer copy, deserialization
- everything is serialized without any data checks or compression
AssetBundles are build atop of
SerializedFiles - binary data with header (indexes of assets, their byte offsets in the file, type tree and type tree hashes)
- prefab loading is faster in editor, but cloning is faster in non-editor builds (to load one large object is slower than to assemble it from small cloneable parts)
- to clone a prefab is much faster than manually assemble it - no additional lookups or typechecks are performed
- it's more performant for UI prefabs with a lot of
Transforms and serialized data to use templates (aka nested prefabs), load from disk only them and then instantiate them to fill the UI with content
- to reduce the amount of serialized data you can store repeated settings in
ScriptableObjects (SO) and make a lot of loaded/instantiated objects to refer to only one SO.
- from version 5.4 the
Transforms of the objects on a scene are layed out contiguously in the memory: the root transforms allocate heap memory buffer for a number of transforms and then stores child's transforms in it. Every reparenting (and child index change) becomes less performant because it involves movement of memory arrays to avoid "holes" in root transform contiguous memory
Instantiate(GO, Transform) overload to avoid overhead of creating root transform memory buffer
- if you know the number of childs of an object - set
Transform.hierarchyCapacity property to allocate the buffer beforehand and avoid multiple reallocations
- be aware of long reparenting in object pool systems
Transform updates are pricey - each change generates
OnTransformChanged internal event which propagates up and down the hierarchy, so try to do only one transform modification each frame. BUT this will be changed with dirty bits implementation (presumably in Unity 5.6, UPD: it's not) and transform modifications will be very cheap
- use "Optimize Game Object" setting in animation import settings to hide unnecessary transforms from hierarchy and reduce transform modification overhead (also it allows Unity to reorder data for better multi-threaded usage in animation skinning).
- UI responds poorly to activation/deactivation (all mesh and geometry recalculations appears in
OnEnable of all UI components); possible workaround is to disable
Canvas component only (and unnecessary
MonoBehaviours to avoid
Update calls) - the UI won't be drawn, no component will be marked as dirty
- UI extensively suffers from method call overheads, so the less components used - the better
Canvas component tires to batch all it's childs for performance reasons, so any change of any children
Drawable component will cause batch recalculations (depth sort involved) which are very expensive; thus good practice is to split (nest)
Canvases and/or extract frequently changed canvas elements to separate (maybe nested)
- all UI always are transparent geometry, no occlusion performed
- reduce a number of
RaycastTargets to make UI more responsive.
Some additional best practices from Unity are presented here: unity3d.com/learn/...