96 lines
6.8 KiB
Markdown
96 lines
6.8 KiB
Markdown
|
# Custom allocator overview
|
||
|
|
||
|
You can use a custom allocator for specific memory allocation needs. To create a custom allocator, it must contain an allocator handle of type [`AllocatorManager.AllocatorHandle`](xref:Unity.Collections.AllocatorManager.AllocatorHandle) and implement the interface, [`AllocatorManager.IAllocator`](xref:Unity.Collections.AllocatorManager.IAllocator). After you create a custom allocator, you need to register it in a global allocator table in [`AllocatorManager`](xref:Unity.Collections.AllocatorManager).
|
||
|
|
||
|
## Add the AllocatorManager.AllocatorHandle type to the custom allocator
|
||
|
|
||
|
A custom allocator must contain an allocator handle of type [`AllocatorManager.AllocatorHandle`](xref:Unity.Collections.AllocatorManager.AllocatorHandle). An allocator handle includes the following:
|
||
|
|
||
|
* `Version`: A 2 byte unsigned version number. Only the lower 15 bits are valid.
|
||
|
* `Index`: A 2 byte unsigned index of the global allocator table obtained during registration.
|
||
|
* Method to add a safety handle to the list of child safety handles of the allocator handle.
|
||
|
* Method to add a child allocator to the list of child allocators of the allocator handle.
|
||
|
* A rewind method to invalidate and unregister all the child allocators, invalidate all the child safety handles of the allocator handle, and increment the allocator handle' `Version` and `OfficialVersion`.
|
||
|
|
||
|
## Implement AllocatorManager.IAllocator interface
|
||
|
|
||
|
To define a custom allocator, you must implement the interface [`AllocatorManager.IAllocator`](xref:Unity.Collections.AllocatorManager.IAllocator) which includes:
|
||
|
|
||
|
* [`Function`](xref:Unity.Collections.AllocatorManager.IAllocator.Function): A property that gets the allocator function of delegate [`TryFunction`](xref:Unity.Collections.AllocatorManager.TryFunction). The allocator function can allocate, deallocate, and reallocate memory.
|
||
|
* [`Try`](xref:Unity.Collections.AllocatorManager.IAllocator.Try(Unity.Collections.AllocatorManager.Block@)): A method that the allocator function invokes to allocate, deallocate, or reallocate memory.
|
||
|
* [`Handle`](xref:Unity.Collections.AllocatorManager.IAllocator.Handle): A property that gets and sets the allocator handle which is of type [`AllocatorManager.AllocatorHandle`](xref:Unity.Collections.AllocatorManager.AllocatorHandle).
|
||
|
* [`ToAllocator`](xref:Unity.Collections.AllocatorManager.IAllocator.ToAllocator): A property that casts the allocator handle index to the enum `Allocator`.
|
||
|
* [`IsCustomAllocator`](xref:Unity.Collections.AllocatorManager.IAllocator.IsCustomAllocator): A property that checks whether the allocator is a custom allocator. An allocator is a custom allocator if its handle `Index` is larger or equal to [`AllocatorManager.FirstUserIndex`](xref:Unity.Collections.AllocatorManager.FirstUserIndex).
|
||
|
* [`IsAutoDispose`](xref:Unity.Collections.AllocatorManager.AllocatorHandle.IsAutoDispose): A property that checks whether the allocator is able to dispose individual allocations. True if disposing an individual allocation is a no-op.
|
||
|
|
||
|
Because `AllocatorManager.IAllocator` implements `IDisposable`, your custom allocator must implement the `Dispose` method.
|
||
|
|
||
|
The following is an example of how to set up the `IAllocator` interface and its required properties except the `Try` and `AllocatorFunction` method:
|
||
|
|
||
|
```c#
|
||
|
// A custom allocator must implement AllocatorManager.IAllocator interface
|
||
|
[BurstCompile(CompileSynchronously = true)]
|
||
|
internal struct ExampleCustomAllocator : AllocatorManager.IAllocator
|
||
|
{
|
||
|
// A custom allocator must contain AllocatorManager.AllocatorHandle
|
||
|
AllocatorManager.AllocatorHandle m_handle;
|
||
|
|
||
|
// Implement the Function property required by IAllocator interface
|
||
|
public AllocatorManager.TryFunction Function => AllocatorFunction;
|
||
|
|
||
|
// Implement the Handle property required by IAllocator interface
|
||
|
public AllocatorManager.AllocatorHandle Handle { get { return m_handle; } set { m_handle = value; } }
|
||
|
|
||
|
// Implement the ToAllocator property required by IAllocator interface
|
||
|
public Allocator ToAllocator { get { return m_handle.ToAllocator; } }
|
||
|
|
||
|
// Implement the IsCustomAllocator property required by IAllocator interface
|
||
|
public bool IsCustomAllocator { get { return m_handle.IsCustomAllocator; } }
|
||
|
|
||
|
// Implement the IsAutoDispose property required by IAllocator interface
|
||
|
// Allocations made by this example allocator are not automatically disposed.
|
||
|
// This implementation can be skipped because the default implementation of
|
||
|
// this property is false.
|
||
|
public bool IsAutoDispose { get { return false; } }
|
||
|
|
||
|
// Implement the Dispose method required by IDisposable interface because
|
||
|
// AllocatorManager.IAllocator implements IDisposable
|
||
|
public void Dispose()
|
||
|
{
|
||
|
// Make sure no memory leaks
|
||
|
Assert.AreEqual(0, m_allocationCount);
|
||
|
|
||
|
m_handle.Dispose();
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The `Try` method tells a custom allocator how to allocate or deallocate memory. The following is an example of the`Try` method where a custom allocator allocates memory from `Allocator.Persistant`, initializes the allocated memory with a user configured value, and increments an allocation count. The custom allocator also decrements the allocation count when deallocating the allocated memory.
|
||
|
|
||
|
[!code-cs[Try method of allocate/deallocate memory](../Unity.Collections.Tests/AllocatorCustomTests.cs#allocator-custom-try)]
|
||
|
|
||
|
Example method `AllocatorFunction` below shows an allocator function of the custom allocator.
|
||
|
|
||
|
[!code-cs[Allocator function](../Unity.Collections.Tests/AllocatorCustomTests.cs#allocator-custom-allocator-function)]
|
||
|
|
||
|
## Global allocator table
|
||
|
|
||
|
The global allocator table in [`AllocatorManager`](xref:Unity.Collections.AllocatorManager) stores all the necessary information for custom allocators to work. When you instantiate a custom allocator, you must register the allocator in the global allocator table. The table stores the following information:
|
||
|
|
||
|
* A pointer to the custom allocator instance
|
||
|
* A pointer to the allocator function of the custom allocator instance
|
||
|
* The current official version of the custom allocator instance, lower 15 bits of a 2 byte unsigned integer value
|
||
|
* A list of child safety handles of native containers that are created using the custom allocator instance
|
||
|
* A list of child allocators that are allocated using the custom allocator instance
|
||
|
* A bit flag indicating whether the custom allocator is able to dispose individual allocations
|
||
|
|
||
|
## Custom allocator example
|
||
|
|
||
|
The following is an example of a custom allocator that has an `AllocatorManager.AllocatorHandle` and initializes the allocated memory with a user configured value and increments the allocation count. It also uses `AllocatorManager.TryFunction` to register the allocator on the global allocator table:
|
||
|
|
||
|
[!code-cs[Custom allocator example](../Unity.Collections.Tests/AllocatorCustomTests.cs#allocator-custom-example)]
|
||
|
|
||
|
## Further information
|
||
|
|
||
|
* [Use a custom allocator](allocator-custom-use.md)
|