Expand description
§Talc Dynamic Memory Allocator
If you find Talc useful, please consider leaving tip via Paypal or Ko-Fi
Note that this README acts as a guide to using Talc. For a brief explanation of what Talc is and why you should or shouldn’t use it, see the repository README.md.
§Table of Contents
Targeting WebAssembly? Check out the WebAssembly README.
§Optional Features
"counters":Talcwill track heap and allocation metrics. Use thecountersassociated function to access them."nightly": Enable nightly-only APIs. Currently allowsTalcLockandTalcCellto implementcore::alloc::Allocator."disable-grow-in-place": Never uses the grow-in-place routine to implementGlobalAllocorAllocator. Intended to reduce size for WebAssembly."disable-realloc-in-place": Never uses grow- or shrink-in-place routines to implementGlobalAllocorAllocator. Intended to reduce size for WebAssembly.
§Setup
There are two choices to make.
----- Wrapper ----- | -- Allocator -- | ----- Source -----
| |
Provides interior | | Manual
mutability, for | |
GlobalAlloc and | | Claim
Allocator APIs | |
| | GlobalAllocSource
--- TalcLock --- | | AllocatorSource
| Talc |
Synchronized via | |
lock_api | | WasmGrowAndClaim
| | WasmGrowAndExtend
--- TalcCell --- | |
| |
Exposes an API with | |
Cell's constraints, | | /Your Own!
free !Sync access | |
| |Talc is the core of the allocator, but usually not useful alone.
- Use
TalcCellfor single-threaded allocation, e.g. using theAllocatorinterface. - Use
TalcLockfor multi-threaded allocation, e.g. as a#[global_allocator]- TalcLock requires a locking mechanism implementing
lock_api::RawMutex, e.g.spinning_top::Raw
- TalcLock requires a locking mechanism implementing
Now you need to decide how you’re going to establish heaps for Talc to allocate from.
- You can manually do this using
claim - You can have an
Sourcedo this for youClaimtries toclaima region of memory you specify, once needed.- Platform-specific sources like
WasmGrowAndExtendretrieve memory from the system as needed. - Some, like
GlobalAllocSource, andAllocatorSourcereserve and release memory dynamically.
See the following two examples of how this looks in practice.
§As a global allocator
use talc::{*, source::Claim};
#[global_allocator]
static TALC: TalcLock<spinning_top::RawSpinlock, Claim> = TalcLock::new(unsafe {
static mut INITIAL_HEAP: [u8; min_first_heap_size::<DefaultBinning>() + 100000] =
[0; min_first_heap_size::<DefaultBinning>() + 100000];
Claim::array(&raw mut INITIAL_HEAP)
});
fn main() {
let mut vec = Vec::with_capacity(100);
vec.extend(0..300usize);
}See examples/global_allocator.rs for a more detailed example.
§Using the Allocator API
// if "nightly" is enabled, core::alloc::Allocator can be used instead of allocator-api2
// #![feature(allocator_api)]
use allocator_api2::alloc::{Allocator, Layout};
use talc::{TalcCell, source::Claim};
fn main() {
let mut heap = [0u8; 10000];
let talc = TalcCell::new(unsafe { Claim::array(&raw mut heap) });
let my_vec = allocator_api2::vec::Vec::<u8, _>::with_capacity_in(234, &talc);
let my_allocation = talc.allocate(Layout::new::<[u32; 16]>()).unwrap();
}See examples/allocator_api.rs for a more detailed example.
§API Overview
Whether you’re using Talc, TalcLock (call lock to get the Talc), or TalcCell (re-exposes the API directly): usage is similar.
§Allocation
TalcLock and TalcCell implement the GlobalAlloc and Allocator traits.
Talc exposes the allocation primitives
allocatetry_allocatedeallocatetry_grow_in_placeshrinktry_realloc_in_place
§Heap Management
claim- establish a heapreserved- query for the region of bytes reserved due to allocationsextend/truncate/resize- change the size of an existing heap
§Statistics - requires "counters" feature
counters- obtains theCountersstruct which contains heap and allocation statistics
Read their documentation for more info.
§Sources
Implementations of Source inform how the allocator establishes and manages the heaps of memory
is allocates from.
Note that you can always use claim/extend/truncate/resize to manage heaps
with some sources, but not others.
Provided Source implementations include:
- Manual heap management
Manual: allocations fail on OOM, manual heap management allowedClaim: claims a heap upon first OOM, useful for initialization
- Automatic heap management
GlobalAllocSourceandAllocatorSource: obtains and frees memory back to another allocatorWasmGrow*: use platform APIs to manage memory
Custom ones can be implemented too.
§Algorithm
This is a dlmalloc-style linked list allocator with boundary tagging and binning, aimed at general-purpose use cases. Allocation is O(n) worst case (but in practice its near-constant time, see microbenchmarks), while in-place reallocations and deallocations are O(1).
The implementation shares a lot of similarities with the TLSF algorithm, but is nowhere near as pure as rlsf.
Additionally, the layout of chunk metadata is rearranged to allow for smaller minimum-size chunks to reduce memory overhead of small allocations. The minimum chunk size is 3 * usize, with a single usize being reserved per allocation. This is more efficient than dlmalloc and galloc, despite using a similar algorithm.
§Migrating from v4 to v5
If you’re using WebAssembly, check out the guide.
The allocator is now stable-by-default. Enable the "nightly" feature if necessary.
The configurable features have changes significantly as well. See the Features section.
You typically won’t use Talc::new anymore. Use TalcLock::new or TalcCell::new.
The heap management APIs: Talc::claim, Talc::extend, Talc::reserved (previously get_allocated_span), Talc::truncate, Talc::resize (new!) changed in various ways. Please check their docs for more info. Span has been removed.
Feel free to reach out or open a PR if you have any unaddressed questions.
§Changelog
The full changelog can be found here. The most recent changes are:
§v5.0.0
Heads up: the API might break between this release and v5.
Check out the migration guide
In general, the allocator got a lot better at doing its job. Also took the opportunity to clean up the APIs, setup, and configuration.
Here are some highlights:
- Performance improvements.
- Size improvements on WebAssembly.
Source(previouslyOomHandler) is now powerful enough for releasing memory automatically.TalcCellintroduced: safe,!Sync, zero-runtime-overhead implementor ofGlobalAllocandAllocator- The crate is now stable-by-default, with an MSRV of Rust 1.64
- Binning configuration for Talc has been added. This primarily benefitted Talc for WebAssembly performance.
Changes:
AssumeUnlockable- the never-safe lock - is gone (good riddance). Instead considerTalcCellandTalcSyncCell.Talc’s heap management APIs have changed. Most notably the base of heaps are now fixed.- The available features have changed, see Features
- WebAssembly-specific things are all in
talc::wasmnow.WasmHandlerbecameWasmGrowAndExtend.WasmGrowAndClaimis the default though. Spanis gone, rest in peace.
And more.
§v5.0.1
Fix broken docs.rs links due to API changes.
§v5.0.2
Change README to avoid <sep> HTML tag usage as crates.io is not a fan.
§v5.0.3
- Update WASM examples to match current API.
- Included checks in
just checkand the GitHub CI to ensure the docs in markdown files don’t break.
Re-exports§
pub use base::binning::DefaultBinning;
Modules§
- base
- This module provides the core allocation mechanism via the
Talctype and related configuration. - cell
TalcCellallows usingTalcas a Rust allocator for single-threaded unsynchronized locking.- source
- An allocator needs a source of memory to allocate from.
With
Talcthis can be manually provided, e.g. usingTalc::claimdirectly. - sync
TalcLockfacilitates usingTalcas a Rust global allocator, or other usage across multiple threads.- wasm
- Talc for WebAssembly
Functions§
- min_
first_ heap_ layout Talccan always successfully perform the first claim if the providedbaseandsizefit the returnedLayout.- min_
first_ heap_ size Talccan always successfully perform the first claim if the providedsizeis at least the returned value.