slabmalloc Build Status Crates.io

Simple slab based malloc implementation in rust, in order to provide the necessary interface to rusts liballoc library. slabmalloc only relies on libcore and is designed to be used in kernel level code as the only interface a client needs to provide is the necessary mechanism to allocate and free 4KiB frames (or any other default page-size on non-x86 hardware).

Build

By default this library should compile using cargo build with nightly versions of the Rust compiler.

Add the following line to the Cargo.toml dependencies:

cfg slabmalloc = ...

Due to the use of const_fn, if you use the library with a stable rustc the unstable feature needs to be disabled:

cfg slabmalloc = { version = ..., default_features = false }

Documentation

API Usage

slabmalloc has two main components described here. However, if you just want to implement a GlobalAlloc trait have a look at the provided example.

It provides a ZoneAllocator to allocate arbitrary sized objects:

```rust let objectsize = 12; let alignment = 4; let layout = Layout::fromsizealign(objectsize, alignment).unwrap();

// We need something that can provide backing memory // (4 KiB and 2 MiB pages) to our ZoneAllocator // (see tests.rs for a dummy implementation). let mut pager = Pager::new(); let page = pager.allocate_page().expect("Can't allocate a page");

let mut zone: ZoneAllocator = Default::default(); // Prematurely fill the ZoneAllocator with memory. // Alternatively, the allocate call would return an // error which we can capture to refill on-demand. unsafe { zone.refill(layout, page)? };

let allocated = zone.allocate(layout)?; zone.deallocate(allocated, layout)?; ```

And a SCAllocator to allocate fixed sized objects:

```rust let objectsize = 10; let alignment = 8; let layout = Layout::fromsizealign(objectsize, alignment).unwrap();

// We need something that can provide backing memory // (4 KiB and 2 MiB pages) to our ZoneAllocator // (see tests.rs for a dummy implementation). let mut pager = Pager::new(); let page = pager.allocate_page().expect("Can't allocate a page");

let mut sa: SCAllocator = SCAllocator::new(object_size); // Prematurely fill the SCAllocator with memory. // Alternatively, the allocate call would return an // error which we can capture to refill on-demand. unsafe { sa.refill(page) };

sa.allocate(layout)?; ```

Performance

No real effort on optimizing or analyzing the performance as of yet. But if you insist, here are some silly, single-threaded benchmark numbers:

log test tests::jemalloc_allocate_deallocate ... bench: 6 ns/iter (+/- 0) test tests::jemalloc_allocate_deallocate_big ... bench: 7 ns/iter (+/- 0) test tests::slabmalloc_allocate_deallocate ... bench: 16 ns/iter (+/- 0) test tests::slabmalloc_allocate_deallocate_big ... bench: 16 ns/iter (+/- 1)

For multiple threads it's beneficial to give every thread it's own instance of a ZoneAllocator. The dealloc can deal with deallocating any pointer on any any thread. The SMP design for that (atomic bitfield ops) is probably not that great of an idea compared to say, jemalloc's fully partitioned approach.

On Naming

We call our allocator slabmalloc; however the name can be confusing as slabmalloc differs a bit from the seminal paper by Jeff Bonwick describing the "slab allocator". slabmalloc really is just a malloc implementation with size classes and different allocators per class (a segregated-storage allocator), while incorporating some of the simple and effective ideas from slab allocation.

Some notable differences for folks familiar with the slab allocator: