### Full example of a custom allocator Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-use.html Complete example of a custom allocator structure, including creation, disposal, and usage with native containers and unsafe memory allocation. ```csharp // Example user structure that contains the custom allocator internal struct ExampleCustomAllocatorStruct { // Use AllocatorHelper to help creating the example custom alloctor AllocatorHelper 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(backgroundAllocator); // Set the initial value to initialize the memory customAllocator.Initialize(initialValue); } // Dispose the custom allocator void DisposeCustomAllocator() { // Dispose the custom allocator customAllocator.Dispose(); // Unregister the custom allocator and dispose it customAllocatorHelper.Dispose(); } // Constructor of user structure public ExampleCustomAllocatorStruct(byte initialValue) { this = default; CreateCustomAllocator(Allocator.Persistent, initialValue); } // Dispose the user structure public void Dispose() { DisposeCustomAllocator(); } // Sample code to use the custom allocator to allocate containers public void UseCustomAllocator(out NativeArray nativeArray, out NativeList nativeList) { // Use custom allocator to allocate a native array and check initial value. nativeArray = CollectionHelper.CreateNativeArray(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(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); } } // Get allocation count from the custom allocator public int AllocationCount => customAllocator.AllocationCount; public void UseCustomAllocatorHandle(out NativeArray nativeArray, out NativeList nativeList) { // Use custom allocator to allocate a native array and check initial value. nativeArray = CollectionHelper.CreateNativeArray(100, customAllocator.ToAllocator, 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(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); } } } internal class ExampleCustomAllocatorStructUsage { // Initial value for the custom allocator. const int IntialValue = 0xAB; // Test code. [Test] public void UseCustomAllocator_Works() { ExampleCustomAllocatorStruct exampleStruct = new ExampleCustomAllocatorStruct(IntialValue); ``` -------------------------------- ### Example custom allocator implementing IAllocator Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-define.html Shows the required structure for a custom allocator, including the AllocatorHandle field and implementations of the IAllocator properties and Dispose method. The Try and AllocatorFunction methods are omitted in this example. ```csharp // 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(); } } ``` -------------------------------- ### Full example of using RewindableAllocator with AllocatorHelper Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-rewindable.html Complete example showing how to create, use, and dispose a RewindableAllocator with AllocatorHelper. It demonstrates allocating a NativeArray, NativeList, and raw byte buffer, then rewinding to free all allocations and verifying that disposed containers throw ObjectDisposedException when ENABLE_UNITY_COLLECTIONS_CHECKS is defined. ```csharp using System; using NUnit.Framework; using Unity.Collections; // This is the example code used in // Packages/com.unity.collections/Documentation~/allocator/allocator-rewindable.md // Example user structure internal struct ExampleStruct { // Use AllocatorHelper to help creating a rewindable alloctor AllocatorHelper rwdAllocatorHelper; // Rewindable allocator property for accessibility public ref RewindableAllocator RwdAllocator => ref rwdAllocatorHelper.Allocator; // Create the rewindable allocator void CreateRewindableAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, int initialBlockSize, bool enableBlockFree = false) { // Allocate the rewindable allocator from backgroundAllocator and register the allocator rwdAllocatorHelper = new AllocatorHelper(backgroundAllocator); // Allocate the first memory block with initialBlockSize in bytes, and indicate whether // to enable the rewindable allocator with individual block free through enableBlockFree RwdAllocator.Initialize(initialBlockSize, enableBlockFree); } // Constructor of user structure public ExampleStruct(int initialBlockSize) { this = default; CreateRewindableAllocator(Allocator.Persistent, initialBlockSize, false); } // Dispose the user structure public void Dispose() { DisposeRewindableAllocator(); } // Sample code to use rewindable allocator to allocate containers public unsafe void UseRewindableAllocator(out NativeArray nativeArray, out NativeList nativeList, out byte* bytePtr) { // Use rewindable allocator to allocate a native array, no need to dispose the array manually // CollectionHelper is required to create/allocate native array from a custom allocator. nativeArray = CollectionHelper.CreateNativeArray(100, ref RwdAllocator); nativeArray[0] = 0xFE; // Use rewindable allocator to allocate a native list, do not need to dispose the list manually nativeList = new NativeList(RwdAllocator.Handle); for (int i = 0; i < 50; i++) { nativeList.Add(i); } // Use custom allocator to allocate a byte buffer. bytePtr = (byte*)AllocatorManager.Allocate(ref RwdAllocator, sizeof(byte), sizeof(byte), 10); bytePtr[0] = 0xAB; } // Free all allocations from the rewindable allocator public void FreeRewindableAllocator() { RwdAllocator.Rewind(); } // Dispose the rewindable allocator void DisposeRewindableAllocator() { // Dispose all the memory blocks in the rewindable allocator RwdAllocator.Dispose(); // Unregister the rewindable allocator and dispose it rwdAllocatorHelper.Dispose(); } } internal class ExampleStructSampleUsage { // Initial block size of the rewindable allocator. const int IntialBlockSize = 128 * 1024; [Test] public unsafe void UseRewindableAllocator_Works() { ExampleStruct exampleStruct = new ExampleStruct(IntialBlockSize); // Allocate native array and native list from rewindable allocator exampleStruct.UseRewindableAllocator(out NativeArray nativeArray, out NativeList nativeList, out byte* bytePtr); // Still able to access the native array, native list and byte buffer Assert.AreEqual(nativeArray[0], 0xFE); Assert.AreEqual(nativeList[10], 10); Assert.AreEqual(bytePtr[0], 0xAB); // Free all memories allocated from the rewindable allocator // No need to dispose the native array and native list exampleStruct.FreeRewindableAllocator(); #if ENABLE_UNITY_COLLECTIONS_CHECKS // Object disposed exception throws because nativeArray is already disposed Assert.Throws(() => { nativeArray[0] = 0xEF; }); // Object disposed exception throws because nativeList is already disposed Assert.Throws(() => { nativeList[10] = 0x10; }); #endif // Dispose the user structure exampleStruct.Dispose(); } } ``` -------------------------------- ### Reinterpret NativeArray as NativeArray Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-aliasing.html Shows how to create a reinterpreted alias of a NativeArray with a different element type. The example creates a NativeArray of length 10, reinterprets it as NativeArray (length 20), modifies the shorts, and reads back an int. Only the original array needs to be disposed; accessing the alias after disposal throws an ObjectDisposedException. ```csharp NativeArray ints = new NativeArray(10, Allocator.Temp); // Length of the reinterpreted array is 20 // (because it has two shorts per one int of the original). NativeArray shorts = ints.Reinterpret(); // Modifies the first 4 bytes of the array. shorts[0] = 1; shorts[1] = 1; int val = ints[0]; // val is 65537 (2^16 + 2^0) // Like with other aliased collections, only the original // needs to be disposed. ints.Dispose(); // Throws an ObjectDisposedException because disposing // the original deallocates the aliased memory. shorts[0] = 1; ``` -------------------------------- ### Use a custom allocator to allocate native containers Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-use.html Shows how to allocate NativeArray, NativeList, and raw byte buffers from a custom allocator. Uses CollectionHelper.CreateNativeArray and CollectionHelper.Dispose for Native- types, and AllocatorManager.Allocate/Free for Unsafe- types. Rewinding the allocator invalidates child safety handles and disposal checks throw an exception. ```csharp // Sample code to use the custom allocator to allocate containers public void UseCustomAllocator(out NativeArray nativeArray, out NativeList nativeList) { // Use custom allocator to allocate a native array and check initial value. nativeArray = CollectionHelper.CreateNativeArray(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(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); } } ``` -------------------------------- ### Declare and create a custom allocator with AllocatorHelper Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-use.html Declares a user structure that contains a custom allocator. Uses AllocatorHelper to allocate and register the allocator, then initializes it with a given initial value. ```csharp // Example user structure that contains the custom allocator internal struct ExampleCustomAllocatorStruct { // Use AllocatorHelper to help creating the example custom alloctor AllocatorHelper 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(backgroundAllocator); // Set the initial value to initialize the memory customAllocator.Initialize(initialValue); } } ``` -------------------------------- ### Use RewindableAllocator to allocate native containers Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-rewindable.html Shows how to allocate NativeArray, NativeList, and a raw byte buffer from a RewindableAllocator. Use CollectionHelper.CreateNativeArray for NativeArray, the allocator handle for NativeList, and AllocatorManager.Allocate for unsafe memory. Individual allocations need not be disposed; call Rewind to free them all. ```csharp // Sample code to use rewindable allocator to allocate containers public unsafe void UseRewindableAllocator(out NativeArray nativeArray, out NativeList nativeList, out byte* bytePtr) { // Use rewindable allocator to allocate a native array, no need to dispose the array manually // CollectionHelper is required to create/allocate native array from a custom allocator. nativeArray = CollectionHelper.CreateNativeArray(100, ref RwdAllocator); nativeArray[0] = 0xFE; // Use rewindable allocator to allocate a native list, do not need to dispose the list manually nativeList = new NativeList(RwdAllocator.Handle); for (int i = 0; i < 50; i++) { nativeList.Add(i); } // Use custom allocator to allocate a byte buffer. bytePtr = (byte*)AllocatorManager.Allocate(ref RwdAllocator, sizeof(byte), sizeof(byte), 10); bytePtr[0] = 0xAB; } ``` -------------------------------- ### Create a rewindable allocator with AllocatorHelper Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-rewindable.html Declares a user structure that uses AllocatorHelper to create and manage a rewindable allocator. The CreateRewindableAllocator method allocates the allocator from a background allocator, registers it, and initializes its first memory block with the given initialBlockSize and optional enableBlockFree flag. ```csharp // Example user structure internal struct ExampleStruct { // Use AllocatorHelper to help creating a rewindable alloctor AllocatorHelper rwdAllocatorHelper; // Rewindable allocator property for accessibility public ref RewindableAllocator RwdAllocator => ref rwdAllocatorHelper.Allocator; // Create the rewindable allocator void CreateRewindableAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, int initialBlockSize, bool enableBlockFree = false) { // Allocate the rewindable allocator from backgroundAllocator and register the allocator rwdAllocatorHelper = new AllocatorHelper(backgroundAllocator); // Allocate the first memory block with initialBlockSize in bytes, and indicate whether // to enable the rewindable allocator with individual block free through enableBlockFree RwdAllocator.Initialize(initialBlockSize, enableBlockFree); } } ``` -------------------------------- ### DisposeCustomAllocator method Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-use.html Shows how to dispose a custom allocator by calling Dispose on the allocator and then on the helper to unregister and dispose it. ```csharp // Dispose the custom allocator void DisposeCustomAllocator() { // Dispose the custom allocator customAllocator.Dispose(); // Unregister the custom allocator and dispose it customAllocatorHelper.Dispose(); } ``` -------------------------------- ### Implement IAllocator.Try for a custom allocator Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-define.html Implements the Try method required by the IAllocator interface. It allocates from Allocator.Persistent, initializes memory with a user-configured value, and increments an allocation count; on deallocation it decrements the count. The method restores the original allocator handle after each operation and returns an error status if allocation or deallocation fails. ```csharp // Value to initialize the allocated memory byte m_initialValue; // Allocation count int m_allocationCount; // Implement the Try method required by IAllocator interface public unsafe int Try(ref AllocatorManager.Block block) { // Error status int error = 0; // Allocate if (block.Range.Pointer == IntPtr.Zero) { // Allocate memory from Allocator.Persistant and restore the original allocator AllocatorManager.AllocatorHandle tempAllocator = block.Range.Allocator; block.Range.Allocator = Allocator.Persistent; error = AllocatorManager.Try(ref block); block.Range.Allocator = tempAllocator; // return if error occurs if (error != 0) return error; // if allocation succeeds, intialize the memory with the initial value and increment the allocation count if (block.Range.Pointer != IntPtr.Zero) { UnsafeUtility.MemSet((void*)block.Range.Pointer, m_initialValue, block.Bytes); Interlocked.Increment(ref m_allocationCount); } return 0; } // Deallocate else { // Deallocate memory from Allocator.Persistant and restore the original allocator AllocatorManager.AllocatorHandle tempAllocator = block.Range.Allocator; block.Range.Allocator = Allocator.Persistent; error = AllocatorManager.Try(ref block); block.Range.Allocator = tempAllocator; // return if error occurs if (error != 0) return error; // if deallocation succeeds, decrement the allocation count if (block.Range.Pointer == IntPtr.Zero) { Interlocked.Decrement(ref m_allocationCount); } return 0; } } ``` -------------------------------- ### Implement custom allocator with AllocatorManager.IAllocator Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-define.html Defines a custom allocator that implements AllocatorManager.IAllocator. It allocates from Allocator.Persistent, initializes memory with a user-provided byte, and tracks allocation/deallocation counts. Must be registered with a Burst-compiled AllocatorFunction delegate for the global allocator table. ```csharp using System; using AOT; using System.Collections.Generic; using System.Threading.Tasks; using NUnit.Framework; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Burst; using System.Threading; // This is the example code used in // Packages/com.unity.collections/Documentation~/allocator/allocator-custom.md // Example custom allocator. The allocator is able to allocate memory from Allocator.Persistant, // if successful, initialize the allocated memory with a user configured value and increment an // allocation count. The allocator is able to deallocate the memory, if successful, decrement // the allocation count. // 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(); } // Value to initialize the allocated memory byte m_initialValue; // Allocation count int m_allocationCount; // Implement the Try method required by IAllocator interface public unsafe int Try(ref AllocatorManager.Block block) { // Error status int error = 0; // Allocate if (block.Range.Pointer == IntPtr.Zero) { // Allocate memory from Allocator.Persistant and restore the original allocator AllocatorManager.AllocatorHandle tempAllocator = block.Range.Allocator; block.Range.Allocator = Allocator.Persistent; error = AllocatorManager.Try(ref block); block.Range.Allocator = tempAllocator; // return if error occurs if (error != 0) return error; // if allocation succeeds, intialize the memory with the initial value and increment the allocation count if (block.Range.Pointer != IntPtr.Zero) { UnsafeUtility.MemSet((void*)block.Range.Pointer, m_initialValue, block.Bytes); Interlocked.Increment(ref m_allocationCount); } return 0; } // Deallocate else { // Deallocate memory from Allocator.Persistant and restore the original allocator AllocatorManager.AllocatorHandle tempAllocator = block.Range.Allocator; block.Range.Allocator = Allocator.Persistent; error = AllocatorManager.Try(ref block); block.Range.Allocator = tempAllocator; // return if error occurs if (error != 0) return error; // if deallocation succeeds, decrement the allocation count if (block.Range.Pointer == IntPtr.Zero) { Interlocked.Decrement(ref m_allocationCount); } return 0; } } // Implement the allocator function of delegate AllocatorManager.TryFunction that is // required when register the allocator on the global allocator table [BurstCompile(CompileSynchronously = true)] [MonoPInvokeCallback(typeof(AllocatorManager.TryFunction))] public static unsafe int AllocatorFunction(IntPtr customAllocatorPtr, ref AllocatorManager.Block block) { return ((ExampleCustomAllocator*)customAllocatorPtr)->Try(ref block); } // Property to get the initial value public byte InitialValue => m_initialValue; // Property to get the allocation count public int AllocationCount => m_allocationCount; // Initialize the allocator public void Initialize(byte initialValue) { m_initialValue = initialValue; m_allocationCount = 0; } } ``` -------------------------------- ### Implement AllocatorFunction for AllocatorManager.TryFunction Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-define.html Defines the allocator function required by the AllocatorManager.TryFunction delegate when registering the custom allocator on the global allocator table. It casts the custom allocator pointer and calls its Try method. The attributes [BurstCompile(CompileSynchronously = true)] and [MonoPInvokeCallback(typeof(AllocatorManager.TryFunction))] are applied. ```csharp // Implement the allocator function of delegate AllocatorManager.TryFunction that is // required when register the allocator on the global allocator table [BurstCompile(CompileSynchronously = true)] [MonoPInvokeCallback(typeof(AllocatorManager.TryFunction))] public static unsafe int AllocatorFunction(IntPtr customAllocatorPtr, ref AllocatorManager.Block block) { return ((ExampleCustomAllocator*)customAllocatorPtr)->Try(ref block); } ``` -------------------------------- ### Create and use an alias of a NativeList Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-aliasing.html Shows how to create an alias of a NativeList using AsArray, modify the shared memory, and dispose only the original. After disposing the original, accessing the alias throws an ObjectDisposedException. ```csharp NativeList nums = new NativeList(10, Allocator.TempJob); nums.Length = 5; // Create an array of 5 ints that aliases the content of the list. NativeArray aliasedNums = nums.AsArray(); // Modify the first element of both the array and the list. aliasedNums[0] = 99; // Only the original need be disposed. nums.Dispose(); // Throws an ObjectDisposedException because disposing // the original deallocates the aliased memory. aliasedNums[0] = 99; ``` -------------------------------- ### Defer disposal of a NativeArray with Dispose(JobHandle) Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-overview.html Shows how to schedule a job that disposes a NativeArray after a dependent job completes. The Dispose(JobHandle) method creates and schedules a disposal job that takes the input handle as a dependency, returning the new job's handle. ```csharp NativeArray nums = new NativeArray(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); ``` -------------------------------- ### Custom allocator usage tests Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-custom-use.html These test methods demonstrate using a custom allocator and its handle to allocate and dispose NativeArray and NativeList, including checks for ObjectDisposedException and multi-threaded allocation. ```csharp // Allocate native array and native list from the custom allocator exampleStruct.UseCustomAllocator(out NativeArray nativeArray, out NativeList nativeList); // Able to access the native array and native list Assert.AreEqual(nativeArray[0], 0xFE); Assert.AreEqual(nativeList[10], 10); // Need to use CollectionHelper.DisposeNativeArray to dispose the native array from a custom allocator CollectionHelper.Dispose(nativeArray) ; // Dispose the native list nativeList.Dispose(); #if ENABLE_UNITY_COLLECTIONS_CHECKS // Object disposed exception throws because nativeArray is already disposed Assert.Throws(() => { nativeArray[0] = 0xEF; }); // Object disposed exception throws because nativeList is already disposed Assert.Throws(() => { nativeList[10] = 0x10; }); #endif // Check allocation count after dispose the native array and native list Assert.AreEqual(0, exampleStruct.AllocationCount); // Dispose the user structure exampleStruct.Dispose(); } ``` ```csharp [Test] public void UseCustomAllocatorHandle_Works() { ExampleCustomAllocatorStruct exampleStruct = new ExampleCustomAllocatorStruct(IntialValue); // Allocate native array and native list from the custom allocator handle exampleStruct.UseCustomAllocatorHandle(out NativeArray nativeArray, out NativeList nativeList); // Able to access the native array and native list Assert.AreEqual(nativeArray[0], 0xFE); Assert.AreEqual(nativeList[10], 10); // Need to use CollectionHelper.DisposeNativeArray to dispose the native array from a custom allocator CollectionHelper.Dispose(nativeArray); // Dispose the native list nativeList.Dispose(); #if ENABLE_UNITY_COLLECTIONS_CHECKS // Object disposed exception throws because nativeArray is already disposed Assert.Throws(() => { nativeArray[0] = 0xEF; }); // Object disposed exception throws because nativeList is already disposed Assert.Throws(() => { nativeList[10] = 0x10; }); #endif // Check allocation count after dispose the native array and native list Assert.AreEqual(0, exampleStruct.AllocationCount); // Dispose the user structure exampleStruct.Dispose(); } ``` ```csharp [Test] public void CustomAllocatorHandle_MultiThreadWorks() { ExampleCustomAllocatorStruct exampleStruct = new ExampleCustomAllocatorStruct(IntialValue); var taskList = new List(); // create 128 native array with another threads for (var i = 0; i < 128; i++) { var task = Task.Run(() => { var nativeArray = CollectionHelper.CreateNativeArray(100, ref exampleStruct.customAllocator, NativeArrayOptions.UninitializedMemory); CollectionHelper.Dispose(nativeArray); }); taskList.Add(task); } Task.WaitAll(taskList.ToArray()); exampleStruct.Dispose(); } ``` -------------------------------- ### Iterate NativeList with GetEnumerator Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/collection-types.html Use GetEnumerator with MoveNext and Current to iterate over a NativeList and calculate the sum of its elements. The first MoveNext call advances to the first element, and MoveNext returns false after the last element. The enumerator is invalid after the list is disposed. ```csharp NativeList nums = new NativeList(10, Allocator.Temp); // Calculate the sum of all elements in the list. int sum = 0; var enumerator = nums.GetEnumerator(); // The first MoveNext call advances the enumerator to the first element. // MoveNext returns false when the enumerator has advanced past the last element. while (enumerator.MoveNext()) { sum += enumerator.Current; } // The enumerator is no longer valid to use after the array is disposed. nums.Dispose(); ``` -------------------------------- ### Dispose a rewindable allocator with Dispose Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-rewindable.html Use this method to dispose a rewindable allocator. It first disposes all memory blocks from Allocator.Persistant, then unregisters the allocator and disposes the memory used to store it. ```csharp // Dispose the rewindable allocator void DisposeRewindableAllocator() { // Dispose all the memory blocks in the rewindable allocator RwdAllocator.Dispose(); // Unregister the rewindable allocator and dispose it rwdAllocatorHelper.Dispose(); } ``` -------------------------------- ### Free all allocations with Rewind Source: https://docs.unity3d.com/Packages/com.unity.collections%406.6/manual/allocator-rewindable.html Use this method to free all allocations from a rewindable allocator by calling Rewind. Rewind invalidates and unregisters all child allocators and invalidates all child safety handles. ```csharp // Free all allocations from the rewindable allocator public void FreeRewindableAllocator() { RwdAllocator.Rewind(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.