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.