Skip to content

Game.Rendering.Utilities.HeapAllocator

Assembly: Game
Namespace: Game.Rendering.Utilities

Type: public struct

Base: System.IDisposable

Summary:
HeapAllocator is a compact, persistent heap manager used for allocating and releasing variable-sized blocks inside a fixed logical heap. It groups free ranges into size/alignment bins (SizeBin) and keeps quick lookup endpoints in a NativeParallelHashMap so adjacent free blocks can be coalesced on release. The allocator is designed for use with Unity's low-level collections (NativeList, NativeParallelHashMap, UnsafeUtility) and uses persistent memory allocations internally. It supports aligned allocations, resizing the logical heap (only increasing), inspection via DebugValidateInternalState, and explicit disposal to free native resources. This struct is not inherently thread-safe and is intended for use on a single thread or with external synchronization.


Fields

  • public const int MaxAlignmentLog2
    Description: Maximum alignment expressed as log2 (63). Used to bound alignment encoding.

  • public const int AlignmentBits
    Description: Number of bits used to encode alignment in SizeBin (6).

  • private Unity.Collections.NativeList<SizeBin> m_SizeBins
    Description: Sorted list of SizeBin entries. Each SizeBin encodes a size class and an alignment log2 and points to a BlocksOfSize list.

  • private Unity.Collections.NativeList<BlocksOfSize> m_Blocks
    Description: Parallel array of BlocksOfSize lists. Each entry holds the free HeapBlock entries for the corresponding size bin.

  • private Unity.Collections.NativeList<int> m_BlocksFreelist
    Description: Free-list of indices in m_Blocks that are currently unused (empty) and can be recycled when adding a new bin.

  • private Unity.Collections.NativeParallelHashMap<ulong, ulong> m_FreeEndpoints
    Description: Maps each free-block endpoint (begin or end) to its counterpart. Used to find adjacent free blocks during coalescing.

  • private ulong m_Size
    Description: Total logical heap size managed by the allocator.

  • private ulong m_Free
    Description: Total free space currently available in the heap.

  • private readonly int m_MinimumAlignmentLog2
    Description: Minimum alignment encoded as log2 (derived from constructor minimumAlignment). All allocations are rounded up to this alignment.

  • private bool m_IsCreated
    Description: Whether the allocator has been created/initialized (used to guard disposal).

Properties

  • public uint MinimumAlignment { get; }
    Description: The minimum alignment in bytes (1 << m_MinimumAlignmentLog2). All allocations will be at least this aligned.

  • public ulong FreeSpace { get; }
    Description: The amount of free space currently available in the heap (m_Free).

  • public ulong UsedSpace { get; }
    Description: The amount of used space in the heap (m_Size - m_Free).

  • public ulong OnePastHighestUsedAddress { get; }
    Description: Returns the one-past-highest used address. If the top of the heap (m_Size) is part of a free block, this reads its endpoint from m_FreeEndpoints to compute the true one-past-used address.

  • public ulong Size { get; }
    Description: Total logical heap size.

  • public bool Empty { get; }
    Description: True if the entire heap is free (m_Free == m_Size).

  • public bool Full { get; }
    Description: True if there is no free space left (m_Free == 0).

  • public bool IsCreated { get; }
    Description: True if the allocator has been initialized and not yet disposed.

Constructors

  • public HeapAllocator(ulong size = 0uL, uint minimumAlignment = 1u)
    Description: Creates a new HeapAllocator. Allocates the internal NativeList/NativeParallelHashMap structures with Allocator.Persistent and sets the minimum alignment. If size > 0 the internal heap is resized and an initial free block covering [0, size) is released into the free pool. The constructor sets m_IsCreated = true; call Dispose() when finished to release internal native memory.

Methods

  • public void Clear()
    Description: Clears all bins and free lists, resets bookkeeping and then Resizes the heap back to the previous size (releasing a single free block covering the whole heap). Useful to reset state while keeping the logical heap size.

  • public void Dispose()
    Description: Disposes all internal Native* containers and any BlocksOfSize contents. After calling Dispose the allocator is no longer IsCreated.

  • public bool Resize(ulong newSize)
    Description: Increases the logical heap size to newSize. Only supports growing; shrinking returns false. When growing it releases a new free block covering the newly added range.

  • public HeapBlock Allocate(ulong size, uint alignment = 1u)
    Description: Allocate a block of the requested size with the requested alignment (alignment is rounded up to MinimumAlignment). Returns a HeapBlock representing the allocated region; if allocation fails returns default(HeapBlock) (Length == 0). The allocator searches for the smallest sufficient size bin with compatible alignment, pops a free block, and cuts the requested allocation out of it (releasing any leftover pieces back as smaller free blocks).

  • public void Release(HeapBlock block)
    Description: Releases a previously-used block back into the free pool. Coalesces with adjacent free blocks using m_FreeEndpoints, inserts the resulting block into the appropriate size/alignment bin, updates m_Free and m_FreeEndpoints.

  • public void DebugValidateInternalState()
    Description: Runtime validation (assertions) of internal invariants. Checks: exactly one non-empty block list per size bin, free lists consistency, stored endpoints correspond to blocks, total free matches m_Free, each free block contributes two endpoints. This uses UnityEngine.Assertions and is intended for debugging under UNITY_ASSERTIONS.

  • private int FindSmallestSufficientBin(SizeBin needle)
    Description: Binary-search to find the index of the smallest size bin that is >= needle. Returns insertion position if not found.

  • private unsafe int AddNewBin(ref SizeBin bin, int index)
    Description: Adds a new SizeBin at the given index, obtaining/allocating a BlocksOfSize entry (from freelist or by appending). Shifts m_SizeBins to make room.

  • private unsafe void RemoveBinIfEmpty(SizeBin bin, int index)
    Description: If the bin's BlocksOfSize has become empty, remove the SizeBin and add its blocksId to the free-list for reuse.

  • private HeapBlock PopBlockFromBin(SizeBin bin, int index)
    Description: Pop a free HeapBlock from the indicated bin, remove its endpoints, decrement m_Free, and possibly remove the bin if empty afterwards.

  • private void RemoveEndpoints(HeapBlock block)
    Description: Removes the begin and end entries for a block from m_FreeEndpoints.

  • private void RemoveFreeBlock(HeapBlock block)
    Description: Remove an arbitrary free block from its bin and update bookkeeping (endpoints, m_Free).

  • private HeapBlock Coalesce(HeapBlock block, ulong endpoint)
    Description: Attempt to coalesce block with a neighboring free block identified by endpoint. If endpoint is adjacent, removes the neighbor free-block and returns the combined block.

  • private HeapBlock Coalesce(HeapBlock block)
    Description: Convenience overload that attempts to coalesce both at begin and end of block.

  • private bool CanFitAllocation(SizeBin allocation, SizeBin bin)
    Description: Predicate determining whether a free block in bin can satisfy allocation. It returns true if the bin's alignment is compatible, or if the bin's size is large enough to accommodate the allocation plus additional padding needed for alignment.

  • private static ulong NextAligned(ulong offset, int alignmentLog2)
    Description: Aligns the given offset up to the alignment (1 << alignmentLog2). Internal utility used to compute aligned addresses.

  • private HeapBlock CutAllocationFromBlock(SizeBin allocation, HeapBlock block)
    Description: Carves out an aligned allocation range from the given free block. Releases any leftover prefix/suffix back to the free pool. Returns the allocated HeapBlock.

Note: Nested types SizeBin and BlocksOfSize implement encoding/decoding of size+alignment and manage the internal list of HeapBlock for each bin; BlocksOfSize itself uses UnsafeUtility + UnsafeList to allocate its own internal array with Allocator.Persistent.

Usage Example

using Game.Rendering.Utilities;

// Create a heap of 64 KiB with a minimum alignment of 16 bytes
var allocator = new HeapAllocator(64 * 1024, minimumAlignment: 16u);

try
{
    // Allocate 1024 bytes aligned to 16
    HeapBlock block = allocator.Allocate(1024, 16u);
    if (block.Length != 0)
    {
        // Use block.begin..block.end for whatever indexing/offsets the consumer expects.
        // ... perform work ...

        // Release when done
        allocator.Release(block);
    }

    // Grow the heap later if needed
    allocator.Resize(128 * 1024);

    // (Optional) validate internal state in debug builds
    allocator.DebugValidateInternalState();
}
finally
{
    // Must dispose to free internal Native containers
    allocator.Dispose();
}

Notes and tips: - HeapBlock is the value type used by this allocator and exposes at least begin, end, and Length (Length == end - begin). Ensure you use the correct HeapBlock definition from the codebase. - This allocator uses persistent native memory (Allocator.Persistent) and UnsafeUtility for internal structures—always call Dispose to avoid leaks. - The allocator only supports growing the heap via Resize; shrinking is not implemented. - DebugValidateInternalState uses Unity assertions and is intended for debugging only (requires UNITY_ASSERTIONS).