Introduction to allocators
Understand how to use an allocator to manage unmanaged memory.
Read time 9 minutesLast updated 8 days ago
An allocator controls the allocation of unmanaged memory. Different allocators organize and track their memory in different ways. The APIs include the following allocators:
Unity.Collections- : The fastest allocator, for short-lived allocations. You can't pass this allocator to a job.
Allocator.Temp - : A short-lived allocator that you can pass into jobs.
Allocator.TempJob - : The slowest allocator for indefinite lifetime allocations. You can pass this allocator to a job.
Allocator.Persistent - Rewindable allocator: A custom allocator that's fast and thread safe, and can rewind and free all your allocations at one point.
To use these types, pass an enum value to select the native allocator type's memory label to use. Alternatively, for low-level allocations where you need custom categorization, you can create and pass a instance directly to allocation functions. If a chosen allocator is full, Unity chooses a fallback allocator instead (usually , or overflow).
AllocatorMemoryLabelTempTempJobTempThe Entities package has its own set of custom prebuilt allocators. For more information, refer to Memory allocators.
Allocator feature comparison
The following table compares the features of the different built-in allocators:
Allocator type | Lifetime | Automatically freed allocations | Can pass to jobs | Min Allocation Alignment (bytes) |
|---|---|---|---|---|
| A frame or a job | Yes | No | 64 |
| Within 4 frames of creation | No | Yes | 16 |
| Indefinite | No | Yes | 16 |
Alternatively, you can create a custom rewindable allocator, which can be passed to jobs, has an indefinite allocation lifetime, and a 64 byte minimum allocation alignment. For more information, refer to Rewindable allocator.
Memory label mapping
The allocators map to memory labels and Memory Profiler regions as follows:
- maps to the label
Allocator.Tempand a Thread-local Temporary Allocator. Depending on the allocating thread, this might show in the Memory Profiler under the allocator regionTempAllocasALLOC_TEMP_TLS,ALLOC_TEMP_MAIN,ALLOC_TEMP_THREADor underALLOC_TEMP_<ThreadName>with allocations under the labelNative > Unity Subsystems > UnsafeUtility > Malloc(Temp) PoolUnsafeUtility.Utility - maps to
Allocator.TempJoband is reported in the Memory Profiler under the allocator regionTempJobAllocpotentially with the post-fixALLOC_TEMP_JOB_4_FRAMES.(JobTemp) - maps to
Allocator.Persistent/Defaultand might show under the allocator region orMallocand eitherALLOC_DEFAULTorALLOC_DEFAULT_MAIN(or depending on the size of the allocation,ALLOC_DEFAULT_THREAD) underALLOC_BUCKET.Native >Unity Subsystems >UnsafeUtility >Malloc(Persistent) UnsafeUtility
Temp allocator
TempTempEach frame, the main thread creates a allocator which it deallocates in its entirety at the end of the frame. Each job also creates one allocator per thread, and deallocates them in their entirety at the end of the job. Because a allocator gets discarded as a whole, you don't need to manually deallocate allocations, and doing so has no effect.
TempTempTempTempTempTempTempTempThere are multiple allocators, and each thread that needs an allocator has one. Unity recycles allocators each frame ensuring a clean memory usage pattern. However, if memory spills over into the fallback allocators, their memory might get fragmented.
TempTempYou can use and to get and set the size for allocators. The minimum alignment of allocations is 64 bytes.
Profiler.GetTempAllocatorSizeProfiler.SetTempAllocatorRequestedSizeTempTempThe sizes for the allocator default to:
Temp- Editor: 16 MB main thread, 256 KB worker threads.
- Players: 4 MB main thread, 256 KB worker threads.
If these sizes are exceeded, allocations on the main thread fall back to the allocator, and on other threads they fall back to a overflow allocator. For more information on temporary native allocations, refer to Thread storage local (TLS) allocator.
TempJobTempShared AtomicSafetyHandle for Temp allocations
All containers allocated with on the same thread use a shared instance rather than each having their own. Most of the time, this isn't an issue because you can't pass allocated collections into a job.
Allocator.TempAtomicSafetyHandleTempHowever, when you use , , , and together with their secondary safety handle, this shared instance is a problem.
NativeHashMapNativeParallelMultiHashMapNativeHashSetNativeListAtomicSafetyHandleA secondary safety handle ensures a that aliases a is invalidated when the is reallocated due to resizing.
NativeArrayNativeListNativeListOperations that invalidate an enumerator for these collection types, or that invalidate the that returns, also invalidate all other previously acquired enumerators. For example, the following throws an error when safety checks are enabled:
NativeArrayNativeList.AsArrayvar list = new NativeList<int>(Allocator.Temp);list.Add(1);// This array uses the secondary safety handle of the list, which is// shared between all Allocator.Temp allocations.var array = list.AsArray();var list2 = new NativeHashSet<int>(Allocator.Temp);// This invalidates the secondary safety handle, which is also used// by the list above.list2.TryAdd(1);// This throws an InvalidOperationException because the shared safety// handle was invalidated.var x = array[0];
TempJob allocator
This type uses a linear style allocator which Unity stores in a area that it allocates from main memory. It's designed for larger temporary allocations that are passed from job to job, and those that might carry data between frames. If the allocations aren't disposed of within 4 frames of their creation, a warning is displayed in the Unity Editor.
TempJobIf this allocator is full, allocations fall back to a overflow allocator. For more information on temporary job allocations, refer to Thread safe linear allocator.
TempJobYou must deallocate allocations within 4 frames of their creation. The 4-frame limit provides some margin for allocations that need to persist across a few frames. The minimum alignment of allocations is 16 bytes.
TempJobTempJobIf a allocation isn't disposed within 4 frames, Unity writes a warning message but the allocation remains valid. Unity doesn't automatically deallocate such allocation, and you must still explicitly dispose it in your code to free the memory.
TempJobExceeding the 4-frame limit has the following consequences:
- Performance degradation: The allocator has a fixed memory pool. If long-lived allocations accumulate and exhaust this pool, subsequent allocations fall back to
TempJob, which is significantly slower.Allocator.Persistent - Memory leak reports: If allocations still exist when the allocator is disposed (for example, when the application exits), Unity reports them as memory leaks when native leak detection is enabled.
TempJob
For collection types, safety-handle checks (via ) validate correct usage and disposal. collection types don't have these safety handles, so they don't perform those usage/disposal validation checks.
NativeAtomicSafetyHandleUnsafeA separate warning mechanism for when a allocation exceeds 4 frames is driven by allocation tracking rather than safety handles. It applies whenever leak detection is enabled. Because collections still allocate through tracked paths (for example, uses ), overdue allocations from collections can still trigger this warning independently of the safety-handle checks. For more information, refer to .
TempJobUnsafeUnsafeListUnsafeUtility.MallocTrackedTempJobUnsafeNativeLeakDetectionIf your job or allocation might regularly exceed 4 frames, use instead.
Allocator.PersistentIf you need an intermediate-lifetime allocator optimized for durations between and , consider using a custom allocator or a rewindable allocator.
TempJobPersistentPersistent allocator
This allocator allocates memory with no time restrictions, is only limited by the amount of free memory on a device, and therefore has no fallback. It can exist for as long as you need it, but the leak detection system only warns you if you don't free the allocated memory and if your handle to the memory was garbage collected. As such, you must deallocate a allocation when you no longer need it. Allocating persistent memory is slower than allocating temporary memory. The minimum alignment of allocations is 16 bytes.
PersistentPersistentDeallocating memory
Each collection retains a reference to the allocator that allocated its memory. This is because you must specify the allocator to deallocate its memory.
- An collection's
Unsafe-method deallocates its memory.Dispose - A collection's
Native-method deallocates its memory and frees the handles needed for safety checks.Dispose - An enumerator's method does nothing. The method exists only to fulfill the
Disposeinterface.IEnumerator<T>
To dispose a collection after the jobs that need it have run, you can use the method. This creates and schedules a job that disposes of the collection, and this new job takes the input handle as its dependency. Effectively, the method defers disposal until after the dependency runs:
Dispose(JobHandle)NativeArray<int> nums = new NativeArray<int>(10, Allocator.TempJob); // Create and schedule a job that uses the array. ExampleJob job = new ExampleJob { Nums = nums }; JobHandle handle = job.Schedule(); // Create and schedule a job that will dispose the array after the ExampleJob has run. // Returns the handle of the new job. handle = nums.Dispose(handle);
IsCreated property
The property of a collection is false only in the following cases:
IsCreated- Immediately after creating a collection with its default constructor.
- After has been called on the collection.
Dispose
Calling on a collection sets to false only for that struct, and not in any copies of the struct. might still be true even after the collection's underlying memory is deallocated in the following situations:
DisposeIsCreatedIsCreated- was called on a different copy of the struct.
Dispose - The underlying memory was deallocated via an alias.