Version: Unity 7.0 Alpha (7000.0)
Language : English
Define a custom allocator
Performance reference

Create and use a custom allocator

Once you’ve defined a custom allocator, you can add it to your structure or class.

Declare and create a custom allocator

The first step is to declare and create the custom allocator. You must do the following:

  • Allocate memory to hold the custom allocator.
  • Register the allocator by adding an entry in a global allocator table.
  • Initialize the allocator if necessary.

The wrapper AllocatorHelper helps in creating a custom allocator. The following examples show how to declare and create a custom allocator defined in the Example custom allocator.

// Example user structure that contains the custom allocator
internal struct ExampleCustomAllocatorStruct
{
    // Use AllocatorHelper to help creating the example custom alloctor
    AllocatorHelper<ExampleCustomAllocator> customAllocatorHelper;

    // Custom allocator property for accessibility
    public ref ExampleCustomAllocator customAllocator => ref customAllocatorHelper.Allocator;

    // Create the example custom allocator
    void CreateCustomAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, byte initialValue)
    {
        // Allocate the custom allocator from backgroundAllocator and register the allocator
        customAllocatorHelper = new AllocatorHelper<ExampleCustomAllocator>(backgroundAllocator);

        // Set the initial value to initialize the memory
        customAllocator.Initialize(initialValue);
    }
}

Use a custom allocator to allocate memory

For Native- collection types, allocation from a custom allocator is similar to built-in allocators. The notable exception is when creating or deallocating a NativeArray, for which you must use CollectionHelper.CreateNativeArray and CollectionHelper.Dispose respectively.

When you use a custom allocator to create a Native- collection type, its safety handle is added to the list of child safety handles of the custom allocator. When you rewind the allocator handle of a custom allocator, it invalidates and unregisters all its child allocators, and invalidates all its child safety handles. For Native- collection types, the disposal safety checks throw an exception if the allocator handle has rewound.

For Unsafe- collection types such as UnsafeList<T>, UnsafeHashMap<TKey, TValue>, and UnsafeStream, pass the custom allocator’s AllocatorManager.Allocate to the collection’s constructor. The collection retains this handle and uses it when you call the collection’s own Dispose method, so you don’t need to allocate or free its memory manually.

To allocate raw memory from a custom allocator, use AllocatorManager.Allocate to allocate the memory and AllocatorManager.Free to deallocate it. The following example demonstrates this raw byte-buffer case:

// Example user structure that contains the custom allocator
internal struct ExampleCustomAllocatorStruct
{
    AllocatorHelper<ExampleCustomAllocator> customAllocatorHelper;

    public ref ExampleCustomAllocator customAllocator => ref customAllocatorHelper.Allocator;

    // Create the example custom allocator
    void CreateCustomAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, byte initialValue)
    {
        // Allocate the custom allocator from backgroundAllocator and register the allocator
        customAllocatorHelper = new AllocatorHelper<ExampleCustomAllocator>(backgroundAllocator);

        // Set the initial value to initialize the memory
        customAllocator.Initialize(initialValue);
    }

    #region allocator-custom-dispose
    // Dispose the custom allocator
    void DisposeCustomAllocator()
    {
        // Dispose the custom allocator
        customAllocator.Dispose();

        // Unregister the custom allocator and dispose it
        customAllocatorHelper.Dispose();
    }
// Sample code to use the custom allocator to allocate containers
public void UseCustomAllocator(out NativeArray<int> nativeArray, out NativeList<int> nativeList)
{
    // Use custom allocator to allocate a native array and check initial value.
    nativeArray = CollectionHelper.CreateNativeArray<int, ExampleCustomAllocator>(100, ref customAllocator, NativeArrayOptions.UninitializedMemory);
    Assert.AreEqual(customAllocator.InitialValue, (byte)nativeArray[0] & 0xFF);
    nativeArray[0] = 0xFE;

    // Use custom allocator to allocate a native list and check initial value.
    nativeList = new NativeList<int>(customAllocator.Handle);
    for (int i = 0; i < 50; i++)
    {
        nativeList.Add(i);
    }

    unsafe
    {
        // Use custom allocator to allocate a byte buffer.
        byte* bytePtr = (byte*)AllocatorManager.Allocate(ref customAllocator, sizeof(byte), sizeof(byte), 10);
        Assert.AreEqual(customAllocator.InitialValue, bytePtr[0]);

        // Free the byte buffer.
        AllocatorManager.Free(customAllocator.ToAllocator, bytePtr, 10);
    }
}

Dispose a custom allocator

To dispose a custom allocator, the following must happen:

  • The custom allocator must rewind its allocator handle which invalidates and unregisters all the allocator handle’s child allocators, and invalidates all its child safety handles.
  • You must unregister the allocator.
  • You must dispose the memory used to store the allocator.

The example method DisposeCustomAllocator in the user structure shows how to dispose a custom allocator:

// Dispose the custom allocator
void DisposeCustomAllocator()
{
    // Dispose the custom allocator
    customAllocator.Dispose();

    // Unregister the custom allocator and dispose it
    customAllocatorHelper.Dispose();
}

Full example of a custom allocator

The following is a full example of how to use a custom allocator:

// Example user structure that contains the custom allocator
internal struct ExampleCustomAllocatorStruct
{
    AllocatorHelper<ExampleCustomAllocator> customAllocatorHelper;

    public ref ExampleCustomAllocator customAllocator => ref customAllocatorHelper.Allocator;

    // Create the example custom allocator
    void CreateCustomAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, byte initialValue)
    {
        // Allocate the custom allocator from backgroundAllocator and register the allocator
        customAllocatorHelper = new AllocatorHelper<ExampleCustomAllocator>(backgroundAllocator);

        // Set the initial value to initialize the memory
        customAllocator.Initialize(initialValue);
    }

    #region allocator-custom-dispose
    // Dispose the custom allocator
    void DisposeCustomAllocator()
    {
        // Dispose the custom allocator
        customAllocator.Dispose();

        // Unregister the custom allocator and dispose it
        customAllocatorHelper.Dispose();
    }

Additional resources

Define a custom allocator
Performance reference