Talc
Talc is a performant and flexible no_std-compatible memory allocator. It's suitable for projects such as operating system kernels, or arena allocation for normal single-threaded apps.
Practical concerns in no_std environments are facilitated, such as custom OOM handling, as well as powerful features like resizing the arena dynamically.
Is your project targetting WASM? Check out usage and comparisons here.
Table of Contents
- Setup
- Benchmarks
- Performance
- Memory Overhead
- Algorithm
- Testing
- General Usage
- Advanced Usage
- Conditional Features
- Changelog
- Support Me
Setup
Use it as an arena allocator via the Allocator API as follows:
use *;
use ;
static mut ARENA: = ;
Or as a global allocator:
use *;
static mut ARENA: = ;
static ALLOCATOR: = new.lock;
See General Usage and Advanced Usage for more details.
Benchmarks
Macrobenchmarks (based on galloc's benchmarks)
The original benchmarks have been modified (e.g. replacing rand with fastrand) in order to alleviate the overhead.
Random Actions Benchmark Results
The number of successful allocations, deallocations, and reallocations within the allotted time.

Heap Efficiency Benchmark Results
The average occupied capacity once filled with random allocations.
| ALLOCATOR | AVERAGE HEAP EFFICIENCY |
|---|---|
| talc | 99.82% |
| linked_list_allocator | 99.82% |
| dlmalloc | 99.81% |
| galloc | 99.81% |
| buddy_alloc | 59.45% |
Heap Exhaustion Benchmark Results
The number of allocation when filling and flushing the heap with a penalty for each cycle.

Notes:
- alignment requirements are inversely exponentially frequent, ranging from 22 bytes to 218, with 22 and 23 being most common
Microbenchmarks (based on simple_chunk_allocator's benchmark)
Pre-fail allocations account for all allocations up until the first allocation failure, at which point heap pressure has become a major factor. Some allocators deal with heap pressure better than others, and many applications aren't concerned with such cases (where allocation failure results in a panic), hence they are seperated out for seperate consideration.
RESULTS OF BENCHMARK: Talc
2221032 allocation attempts, 1564703 successful allocations, 26263 pre-fail allocations, 1553755 deallocations
CATEGORY | OCTILE 0 1 2 3 4 5 6 7 8 | AVERAGE
---------------------|--------------------------------------------------------------------------|---------
All Allocations | 21 42 63 63 84 84 105 189 54327 | 123 ticks
Pre-Fail Allocations | 42 63 63 63 84 84 105 126 1743 | 93 ticks
Deallocations | 21 63 84 84 105 126 231 315 21357 | 178 ticks
RESULTS OF BENCHMARK: Buddy Allocator
2370094 allocation attempts, 1665891 successful allocations, 17228 pre-fail allocations, 1659287 deallocations
CATEGORY | OCTILE 0 1 2 3 4 5 6 7 8 | AVERAGE
---------------------|--------------------------------------------------------------------------|---------
All Allocations | 21 42 42 42 42 63 63 63 15519 | 52 ticks
Pre-Fail Allocations | 21 42 42 42 42 63 63 63 756 | 75 ticks
Deallocations | 42 63 63 63 63 84 84 126 16107 | 94 ticks
RESULTS OF BENCHMARK: Dlmalloc
2176317 allocation attempts, 1531543 successful allocations, 25560 pre-fail allocations, 1520414 deallocations
CATEGORY | OCTILE 0 1 2 3 4 5 6 7 8 | AVERAGE
---------------------|--------------------------------------------------------------------------|---------
All Allocations | 42 63 84 147 168 189 210 294 19026 | 170 ticks
Pre-Fail Allocations | 42 63 105 147 147 168 189 273 16863 | 168 ticks
Deallocations | 42 105 126 126 189 252 294 399 19509 | 240 ticks
RESULTS OF BENCHMARK: Galloc
282268 allocation attempts, 207553 successful allocations, 23284 pre-fail allocations, 197680 deallocations
CATEGORY | OCTILE 0 1 2 3 4 5 6 7 8 | AVERAGE
---------------------|--------------------------------------------------------------------------|---------
All Allocations | 42 63 63 294 12306 26901 41748 45906 128877 | 19106 ticks
Pre-Fail Allocations | 42 42 42 42 63 63 63 630 21147 | 663 ticks
Deallocations | 42 63 84 84 147 252 378 735 18018 | 288 ticks
RESULTS OF BENCHMARK: Linked List Allocator
137396 allocation attempts, 107083 successful allocations, 24334 pre-fail allocations, 96915 deallocations
CATEGORY | OCTILE 0 1 2 3 4 5 6 7 8 | AVERAGE
---------------------|--------------------------------------------------------------------------|---------
All Allocations | 42 4452 9786 16296 24108 33894 45801 56763 1199415 | 28868 ticks
Pre-Fail Allocations | 42 924 2310 4032 6216 8883 12537 18039 902979 | 11427 ticks
Deallocations | 42 3423 7224 11550 16485 22092 28833 37569 98679 | 19085 ticks
Notes:
- number of pre-fail allocations is more noise than signal due to random allocation sizes
- alignment requirements are inversely exponentially frequent, ranging from 22 bytes to 218, with 22 and 23 being most common
Performance
O(n) worst case allocations. In practice, it's usually fast. See the benchmarks below.
Deallocation is always O(1), reallocation is usually O(1) unless in-place allocation fails.
Memory Overhead
Allocations have a overhead of one usize each, typically. The chunk size is at minumum 3 * usize, so tiny allocations will have a lot of overhead.
This improves on Galloc (another boundary-tagging allocator), which has a minimum chunk size of 4 * usize.
Algorithm
This is a dlmalloc-style linked list allocator with boundary tagging and bucketing, aimed at general-purpose use cases.
The main differences compared to Galloc, using a similar algorithm, is that Talc doesn't bucket by alignment at all, assuming most allocations will require at most a machine-word size alignment, so expect Galloc to be faster where lots of small, large alignment allocations are made. Instead, a much broader range of bucket sizes are used, which should often be more efficient.
Additionally, the layout of chunk metadata is rearranged to allow for smaller minimum-size chunks to reduce memory overhead of small allocations.
Testing
Tests on most of the helper types and Talc functions.
Other than that, lots of fuzzing of the allocator.
General Usage
Here is the list of Talc methods:
- Constructors:
newwith_arena
- Information:
get_arena- returns the current arena memory regionget_allocatable_span- returns the current memory region in which allocations could occurget_allocated_span- returns the minimum span containing all allocated memory
- Management:
init- initialize or re-initialize the arena (forgets all previous allocations, if any)extend- extend the arena (or initialize, if uninitialized)truncate- reduce the extent of the arenalock- wraps theTalcin aTalck, which supports theGlobalAllocandAllocatorAPIs
- Allocation:
mallocfreegrowshrink
See their docs for more info.
Span is a handy little type for describing memory regions, because trying to manipulate Range<*mut u8> or *mut [u8] or base_ptr-size pairs tends to be inconvenient or annoying. See Span::from* and span.to_* functions for conversions.
Advanced Usage
The most powerful feature of the allocator is that it has a modular OOM handling system, allowing you to perform any actions, including directly on the allocator or reporting the offending allocation, allowing you to fail out of or recover from allocation failure easily. As an example, recovering my extending the arena is implemented below.
use *;
;
Conditional Features
lock_api(default): Provides theTalcklocking wrapper type that implementsGlobalAlloc.allocator(default): Provides anAllocatortrait implementation viaTalck.
Changelog
v2.2.0
- Added
dlmallocto the benchmarks. - WASM should now be fully supported via
TalckWasm. Let me know what breaks ;)- Find more details here.
v2.1.0
- Tests are now passing on 32 bit targets.
- Documentation fixes and improvements for various items.
- Fixed using
lock_apiwithoutallocator. - Experimental WASM support has been added via
TalckWasmon WASM targets.
v2.0.0
- Removed dependency on
spinand switched to usinglock_api(thanks Stefan Lankes)- You can specify the lock you want to use with
talc.lock::<spin::Mutex<()>>()for example.
- You can specify the lock you want to use with
- Removed the requirement that the
Talcstruct must not be moved, and removed themovfunction.- The arena is now used to store metadata, so extremely small arenas will result in allocation failure.
- Made the OOM handling system use generics and traits instead of a function pointer.
- Use
ErrOnOomto do what it says on the tin.InitOnOomis similar but inits to the given span if completely uninitialized. ImplementOomHandleron any struct to implement your own behaviour (the OOM handler state can be accessed fromhandle_oomviatalc.oom_handler).
- Use
- Changed the API and internals of
Spanand other changes to passmiri's Stacked Borrows checks.- Span now uses pointers exclusively and carries provenance.
- Updated the benchmarks in a number of ways, notably adding
buddy_allocand removingsimple_chunk_allocator.
Support Me
This'll go towards keeping me alive, getting me through university, and allowing me to keep working on my OSS projects.
Appreciate it!
