Unity’s managed memory system is a C# scripting environment based on the Mono or IL2CPP Virtual Machines (VMs). The benefit of the managed memory system is that it manages the release of memory, so you don’t need to manually request the release of memory through your code.
Unity’s managed memory system uses a garbage collector and a managed heap to automatically free memory allocations when your scripts no longer hold any references to those allocations. This helps safeguard against memory leaks. Memory leaks occur when memory is allocated, the reference to it is lost, and then the memory is never freed because it needs a reference to it to free it.
This memory management system also guards memory access, which means that you can’t access memory that has been freed, or that was never valid for your code to access. However, this memory management process impacts runtime performance, because allocating managed memory is time-consuming for the CPU. Garbage collection might also stop the CPU from doing other work until it completes.
When a method is called, the scripting back end copies the values of its parameters to an area of memory reserved for that specific call, in a data structure called a call stack. The scripting back end can quickly copy data types that occupy a few bytes. However, it’s common for objects, strings, and arrays to be much larger, and it’s inefficient for the scripting back end to copy these types of data on a regular basis.
All non-null reference-type objects and all boxed value-typed objects in managed code must be allocated on the managed heap.
It’s important that you are familiar with value and reference types, so that you can effectively manage your code. For more information, see Microsoft’s documentation on value types, and reference types.
When an object is created, Unity allocates the memory required to store it from a central pool called the heap, which is a section of memory that your Unity project’s selected scripting runtime (Mono or IL2CPP) automatically manages. When an object is no longer in use, the memory it once occupied can be reclaimed and used for something else.
Unity’s scripting back ends use a garbage collector to automatically manage your application’s memory, so that you don’t need to allocate and release these blocks of memory with explicit method calls. Automatic memory management requires less coding effort than explicit allocation/release and reduces the potential for memory leaks.
The managed heap is a section of memory that your Unity project’s selected scripting runtime (Mono or IL2CPP) automatically manages.
In the above diagram, the blue box represents a quantity of memory that Unity allocates to the managed heap. The white boxes within it represent data values that Unity stores within the managed heap’s memory space. When additional data values are needed, Unity allocates them free space from the managed heap (annotated A).
The above diagram shows an example of memory fragmentation. When Unity releases an object, the memory that the object occupied is freed up. However, the free space doesn’t become part of a single large pool of “free memory.”
The objects on either side of the released object might still be in use. Because of this, the freed space is a “gap” between other segments of memory. Unity can only use this gap to store data of identical or lesser size than the released object.
This situation is called memory fragmentation. This happens when there is a large amount of memory available in the heap, but it is only available in the “gaps” between objects. This means that even though there is enough total space for a large memory allocation, the managed heap can’t find a large enough single block of contiguous memory to assign to the allocation.
If a large object is allocated and there is insufficient contiguous free space to accommodate it, as illustrated above, the Unity memory manager performs two operations:
The unexpected expansion of the heap can be problematic. Unity’s garbage collection strategy tends to fragment memory more often. You should be aware of the following:
GC.Collect
to make sure the state of these references is up to date. Bear in mind that:
UnloadUnusedAssets
is not triggered automatically, only manually and on scene changes. If you want to free that memory earlier, which can be crucial, for example, for fullscreen RenderTextures on platforms with low RAM, you should call Destroy on the objects to make optimal use of the memory you have.UnloadUnusedAssets
or GC.Collect
triggers a CPU-intensive process that you might want to avoid during Gameplay.