The Rust standard library provides two allocator structs: std::alloc::{System, Global}.
What's the relation and the difference between them?
The Rust standard library provides two allocator structs: std::alloc::{System, Global}.
What's the relation and the difference between them?
Please note that the following explanations focus on Rust 1.60 nightly. Some things might change, when the new allocator_api feature gets stabilized.
TL;DR: std::alloc::System glues the standard library types that need memory allocations to the memory allocation mechanism of the operating system (such as: libc: malloc -> brk()/mmap()). alloc::alloc::Global is
the default implementation for the allocator_api feature, which can be used to alter allocations of Vectors, Boxes, etc.
Whereas std::alloc::System actually comes from the standard library, std::alloc::Global is in fact a re-export from alloc::alloc::Global.
When you register a custom global allocator, you need a type that implements the trait core::alloc::GlobalAlloc. When you assign this type to a global static variable with the #[global_allocator] attribute, Rust lets the following "magic symbols" point to the corresponding implementations of the trait functions.
extern "Rust" {
// These are the magic symbols to call the global allocator. rustc generates
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
// (the code expanding that attribute macro generates those functions), or to call
// the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
// otherwise.
// The rustc fork of LLVM also special-cases these function names to be able to optimize them
// like `malloc`, `realloc`, and `free`, respectively.
#[rustc_allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
#[rustc_allocator_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind]
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
#[rustc_allocator_nounwind]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}
There exist higher-level Rust wrappers for these magic functions:
alloc::alloc::{alloc, alloc_zeroed, dealloc, realloc}.
std::alloc::System is the default #[global_allocator] allocator for the target you are compiling for (Unix, Windows, ...). For example, on UNIX-systems it will use libc::malloc, which will use mmap() and brk() syscalls to obtain heap memory from the operating system.
alloc::alloc::Global however is part of the allocator_api-feature which can be seen as a finer-grained selection of an allocator that should get used. The Allocator API brings the trait alloc::alloc::Allocator that gets implemented by alloc::alloc::Global. By default, it forwards requests to alloc::alloc::{alloc, alloc_zeroed, dealloc, realloc}. Typical types provided by the alloc crate (Vector, BTreeMap, Box, ...) all allow to chose a custom alloc::alloc::Allocator. The default value for this is alloc::alloc::Global.
To give an example, this is the type definition of alloc::vec::Vec (note the "Global):
pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
buf: RawVec<T, A>,
len: usize,
}
You can use custom allocators (the allocator_api-feature) for example to force page-aligned allocations in a Box<T>.