Once you’ve defined a custom allocator, you can add it to your structure or class.
The first step is to declare and create the custom allocator. You must do the following:
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);
}
}
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);
}
}
To dispose a custom allocator, the following must happen:
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();
}
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();
}