Read on to find out how memory management works in Unity, how to diagnose performance issues related to memory allocation, what settings are available to fix these issues, and how to use them.
Unity uses three memory management layers to handle memory in your application:
Internally, Unity has different ways to allocate native memory, known as allocators. This blog post will focus on two:
When we request new memory from the memory management system, we check the size first. If it’s smaller than a certain threshold, we ask the bucket allocator for memory. Once the bucket allocator has filled up, we still need to allocate memory from somewhere, so these small allocations will come from the dynamic heap allocator. Falling back to the dynamic heap allocator is slower, and adding lots of small allocations into the dynamic heap can lead to increased fragmentation of the dynamic heap.
In summer 2020, Unity provided support for Moon Studios when they were working to port Ori and the Will of the Wisp to Nintendo Switch. You can learn more about how we worked together to scale the project for this target platform in this case study.
Moon Studios and Unity Accelerate Solutions (formerly Unity Professional Services) analyzed sections of code together, finding ways to tweak the particle systems and reduce memory usage. “When you’re targeting 60 fps on Nintendo Switch, you have to make sure every single aspect is optimized, including simulation, streaming, rendering, and graphics,” says studio founder Gennadiy Korol.
Ori and the Will of the Wisps pushes the Nintendo Switch very hard in terms of memory use. The Accelerate Solutions team helped Moon make sure they were getting the best from these layers, focusing on native memory allocation.
Working with the team from Moon Studios, the Unity team measured the number of allocations from the different allocators. They also looked at the amount of memory allocated from each, which showed that the game was filling up some of the bucket allocators before even reaching the start of gameplay.
Increasing the size of the bucket allocator allowed extra room for small allocations that happen when playing the game. Allocating these small blocks from the bucket allocator gives the game a performance boost, helping it to hit the 60 fps target. The small allocations no longer come from the dynamic heap allocator, so this allocator contains just large blocks of memory. The allocator is less fragmented, which keeps the game running smoothly for longer.
Following the collaboration with Moon, the Accelerate Solutions team worked with the Optimization team, who developed the memory allocator customization feature that is now available in 2021 LTS.
Before 2021 LTS, balancing memory setup has been inaccessible to Unity users, but now you too can make sure you’re getting the best memory utilization for your game. Measure how much memory is used by different allocators, then customize their size to suit your game. Check out the documentation, and let us know how it’s going – we’d love to hear about your experience. Please join us on the Unity forum to share your project performance analysis, improvements, and challenges faced along the way.