Understanding The Memcached Source Code — Slab III

Holmes He
source code
Published in
3 min readDec 12, 2018


Photo by Sharon McCutcheon on Unsplash

Slab allocator is the core module of the cache system, which largely determines how efficient the bottleneck resource, memory, can be utilised. The other 3 parts, namely, LRU algorithm for entry expiration; and an event driven model based on libevent; and the consistent harsh for data distribution, are built around it.

Slab I
Slab II
Slab III (this article)
Event driven I

Last time we saw the memory allocating process, which further formulates slabs and the derivative “free lists” (a.k.a., slots). This time we will examine how to take advantage of the established data structures to “slab allocate / release” memory chunks which will be used to store items.

Firstly, we look at


which is opposite to the discussed do_slabs_free.

Note that the “public” interface of do_slabs_alloc is slabs_alloc which is basically a thread-safe wrapper that locks the core data structures manipulated by the Memcached instance that is configured as multi-threaded.

static void *do_slabs_alloc(const size_t size, unsigned int id, unsigned int *total_chunks,
unsigned int flags) {
slabclass_t *p;
void *ret = NULL;
item *it = NULL;
p = &slabclass[id]; // scr: ------------------------------> 1)
if (total_chunks != NULL) {
*total_chunks = p->slabs * p->perslab; // scr: -------> 2)
/* fail unless we have space at the end of a recently allocated page,
we have something on our freelist, or we could allocate a new page */
if (p->sl_curr == 0 && flags != SLABS_ALLOC_NO_NEWPAGE) { // scr: --> *)
do_slabs_newslab(id); // scr: ------------------------> 3)

if (p->sl_curr != 0) {
/* return off our freelist */
it = (item *)p->slots; // scr: -----------------------> 4)
p->slots = it->next;
if (it->next) it->next->prev = 0;
/* Kill flag and initialize refcount here for lock safety in slab
* mover's freeness detection. */
it->it_flags &= ~ITEM_SLABBED; // scr: ---------------> 5)
it->refcount = 1;
ret = (void *)it; // scr: ----------------------------> 6)
} else {
ret = NULL;

return ret;

1) For item allocation, id indicates the slab class that suits the requested item size best. In other words, id is selected using the actual item size, the process of which will be discussed very soon.

2) total_chunks is the parameter that outputs the total number of memory chunks (entries in the free list) available for the slab class. if (total_chunks != NULL) suggests that the argument is optional.

*) As the name indicates, SLABS_ALLOC_NO_NEWPAGE (flags) prevents this method to allocate new slab when there is no memory chunk available. This option is not used in the normal path of item allocation, hence is ignored for now.

3) When there is no free memory chunk, allocate a new slab. Here p->sl_curr indicates the number of available chunks, whose value decreases each time this method got called (in step 5 bellow).

Conversely, this field is increased in do_slabs_free. Note that new slab has also been covered from here.

4) Remove the front element (f) from the free list, and set it to it.

In do_slabs_free, an element is added to the front of the free list.

5) Clear the ITEM_SLABBED for the chuck (f), set its reference count to 1, and reduce p->sl_curr by 1.

Likewise, this flag is set in do_slabs_free.

6) Return (f).

Next, we look at the process of determining the id based on item size, the workhorse method of which is


unsigned int slabs_clsid(const size_t size) {

if (size == 0)
return 0;
while (size > slabclass[res].size)
if (res++ == power_largest) /* won't fit in the biggest slab */
return 0;
return res;

slabs_clsid consists mainly of a while loop that linear search the possible smallest slab class that can contain the requested size. This method is called from do_item_alloc before slabs_alloc. We will discuss do_item_alloc in the following post.

item *do_item_alloc(char *key, const size_t nkey, const unsigned int flags,
const rel_time_t exptime, const int nbytes,
const uint32_t cur_hv) {
unsigned int id = slabs_clsid(ntotal);
if (id == 0)
return 0;
it = slabs_alloc(ntotal, id, &total_chunks, 0);

Originally published at holmeshe.me.