Deallocating Temp Memory: Part 3
Continuing the series, today we look specifically at “overflow” allocations in the Temp
allocator. We’ve seen that there’s no need to explicitly deallocate Temp
memory because it all gets cleared every frame, but do we need to deallocate “overflow” allocations that didn’t fit inside the block of automatically-cleared memory? Today we’ll find out!
Overflow Allocations
We don’t really know at this point exactly how the Temp
allocator works. However, we have evidence pointing us toward certain behaviors. It seems as though it allocates from a fixed-size block of memory. If that block runs out, an alternative allocator is used to handle the “overflow.” Every frame, Unity automatically clears all allocations from the block. But does it automatically free all the allocations from the alternative allocator that handles overflow?
It looks from the distance graph that the alternative allocator is TempJob
. We’ve also seen that TempJob
allocations must be explicitly deallocated. Does this mean that overflow allocations must be explicitly deallocated, too? Today’s test is designed to find out.
Writing the Test
First, we need to use up the whole fixed-size block that the Temp
allocator uses. Then we can perform an allocation to see if there are any warnings from Unity stating that we didn’t deallocate it, like we’d get when using TempJob
or Persistent
. To make the allocation especially visible, we’ll allocate and clear 100 MB so it appears clearly in the macOS Activity Monitor.
using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; unsafe class TestScript : MonoBehaviour { void Start() { // Use up the whole fixed-size block of memory void* last = null; while (true) { void* cur = UnsafeUtility.Malloc(4, 4, Allocator.Temp); if (last != null && (ulong)cur - ((ulong)last + 4) > 16) { break; } last = cur; } // Perform one big allocation and clear it const int size = 1024*1024*100; void* big = UnsafeUtility.Malloc(size, 4, Allocator.Temp); UnsafeUtility.MemClear(big, size); } }
Running the Test
Running this with Unity 2019.2.15f1 on macOS 10.15.2, we don’t get any warnings stating that we didn’t deallocate any memory. We would expect to see these with TempJob
or Persistent
allocations, but we’re not.
Next, let’s check to see if there is a memory leak that Unity isn’t telling us about. An easy way of doing that is to look at the Unity process’ memory usage in Activity Monitor before entering play mode. Then, look again after entering play mode to see if the value is about 100 MB higher, which is the size of the “big” overflow allocation.
On my test system, Unity was using about 538 MB of RAM before entering play mode and 550 MB after entering play mode. The extra 12 MB doesn’t account for the 100 MB allocation, only play mode overhead, so there hasn’t been a memory leak.
Conclusions
Even overflow Temp
allocations seem to be automatically deallocated by Unity every frame. We get no warnings and there isn’t a memory increase that would indicate a leak. We don’t know how, but Unity presumably keeps track of the Temp
allocations even when allocated outside of the fixed-size block and deallocates them for us. This reduces the complexity of the code we write, since we don’t need to worry whether our Temp
allocation was from the fixed-size block or from an alternate allocator. We simply don’t need to ever explicitly deallocate it since Unity will do that for us.