Skip to content

[Feature] Adopt new allocators for fast allocating and reduce RSS #789

Description

@kexianda

Feature Category

Performance Optimization

Problem / Use Case

Motivation

HashStringAllocator and memory::StlAllocator are Bolt's low-level
allocators, while AlignedBuffer provides the underlying buffer allocation
mechanism for bolt::vector.

HashStringAllocator/ and memory::StlAllocator suffer from performance issues, and AlignedBuffer has lots of internal fragmentation.

  1. memory::StlAllocator calls the MemoryPool API directly, which has the
    following drawbacks:

    • The mutex and locking mechanism in MemoryPool::allocate is expensive,
      resulting in poor allocation performance.
    • Mandatory alignment wastes memory.
  2. HashStringAllocator was introduced to avoid calling the inefficient
    MemoryPool::allocate method directly. Its arena-based memory management
    also helps reduce memory fragmentation. However, its implementation has the
    following drawbacks:

    • Free-list lookup is linear and therefore becomes a performance bottleneck.
    • Allocation metadata, such as the pointer and size of every allocation, is
      stored in a map and incurs substantial overhead.
  3. AlignedBuffer always rounds its capacity up to either a power of two or
    1.5 times the previous capacity, which can result in wasted memory due to
    internal fragmentation.

Proposed Solution

  1. Introduce SlabAllocator as a replacement for memory::StlAllocator.
    SlabAllocator reserves memory from MemoryPool in batches, reducing the
    frequency of calls to MemoryPool.

  2. Introduce MonotonicMemoryResource and its corresponding allocator. They
    provide extremely fast allocation and deallocation while eliminating the
    metadata overhead of HashStringAllocator.

  3. Use allocation strategies tailored to specific use cases. For fixed-size
    allocations, account only for SIMD alignment and avoid allocating excess
    capacity. For buffers that grow over time, retain the existing growth
    strategy to preserve performance.

============================================================================

[...]s/unstable/SlabAllocatorBenchmark.cpp relative time/iter iters/s.
HashStringAllocatorFifoAllocFree256K_8Threads 58.47ns 17.10M.
AlignedStlAllocatorFifoAllocFree256K_8Threads 10.372% 563.70ns 1.77M
SlabAllocatorFifoAllocFree256K_8Threads 384.63% 15.20ns 65.79M.
case time/iter allocations requested bytes reserved bytes external peak RSS
HashStringAllocatorAllocateNoFree 4.36s 54,216,550 1,073,741,833 0 1,354,144 KiB
MonotonicMemoryResourceAllocateNoFree 809.35ms 54,216,550 1,073,741,833 2,145,386,496 1,099,896 KiB
  • SlabAllocator is ~4x faster than HashStringAllocator, and ~38x faster than memory::StlAllocator
  • MonotonicMemoryResource is ~5x faster than HashStringAllocator

References / Prior Art

No response

Importance

Blocker (Cannot use Bolt without this)

Willingness to Contribute

Yes, I can submit a PR

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions