Understanding the managed heap Flashcards
Key problems with the heap
Unity does not often release the memory pages allocated to the managed heap when it expands; it optimistically retains the expanded heap, even if a large portion of it is empty. This is to prevent the need to re-expand the heap should further large allocations occur.
On most platforms, Unity eventually releases the pages used by empty portions of the managed heap back to the operating system. The interval at which this occurs is not guaranteed and should not be relied upon.
The address space used by the managed heap is never returned to the operating system.
For 32-bit programs, this can lead to address space exhaustion if the managed heap expands and contracts many times. If a program’s available memory address space is exhausted, the operating system will terminate the program.
For 64-bit programs, the address space is sufficiently large that this is extremely unlikely to occur for programs whose running time does not exceed the average human lifespan.
Temporary allocations
The Unity Profiler does not track these allocations when they occur off the main thread.
Always profile managed allocations with a development build
on the target device.
Closures and anonymous methods
First, all method references in C# are reference types, and are therefore allocated on the heap. Temporary allocations can be easily created by passing a method reference as an argument. This allocation occurs regardless of whether the method being passed is an anonymous method or a predefined one.
Second, converting an anonymous method to a closure significantly increases the amount of memory required to pass the closure to method receiving it.
In general, it is best to avoid closures in C# whenever possible. Anonymous methods and method references should be minimized in performance-sensitive code, and especially in code that executes on a per-frame basis.
Boxing
Boxing is one of the most common sources of unintended temporary memory allocations found in Unity projects. It occurs whenever a value-typed value is utilized as a reference type; this most often occurs when passing primitive value-typed variables (such as int and float) to object-typed methods.
Boxing should be avoided wherever possible when writing C# code for Unity runtimes.
Identifying boxing
::Box(…)
Box(…)
_Box(…)
Dictionaries and enums
One common cause of boxing is the use of enum types as keys for Dictionaries.
To solve this problem, it is necessary to write a custom class that implements the IEqualityComparer interface and assign an instance of that class as the Dictionary’s comparer (Note: This object is usually stateless, and therefore can be reused with different Dictionary instances to save memory).
Foreach loops
the CPU performance difference compared to equivalent Array-based code remains, due to method-call overhead
Array-valued Unity APIs
All Unity APIs that return arrays create a new copy of the array each time they are accessed.