Many developers use Memcached for their projects, but only a few of them know exactly how this caching solution works. Let’s dive into the world of Memcached to learn more about its memory allocation and how to prevent fragmented memory for your Java and PHP applications.
Memcached uses a slab memory allocation, instead of allocating the memory on an item by item basis. This allows for improvement to memory usage and prevents memory fragmentation, when information expires from the cache. In this case, memory is allocated in blocks of 1MB in size. Each slab is separated into a number of identical blocks. When you try to store a specified value into the cache, Memcached checks its size and defines which slab contains a suitably sized allocation. If such a slab already exists, the value is written to the block within the slab. If there are no existing blocks that are suitable, then a new slab is created and separated into blocks of an appropriate size. If you update an existing item with larger data than the existing block allocation for that key, then the key is reallocated into a suitable slab.
As a result, you get multiple pages allocated within the Memcached memory. Each page is 1MB in size and is divided into a different number of chunks. Every instance has multiple pages distributed and a new page is always created when a new value needs to be created, requiring a chunk of a particular size. A slab may contain multiple pages, and each page consists of an equal number of chunks.
Such a memory allocation method ensures that memory does not get fragmented. But remember that having a relatively small number of items within each chunk size, may waste a lot of memory with just a few chunks in each allocated page. The efficiency of using such an approach fully depends on the distribution of the objects that you want to store.
The Jelastic Platform allows you to change the coefficient of slab growth while the application is running. Simply click the Config button for Memcached and edit your memcached file, which is located in the conf directory.
Let’s perform a small test!
OPTIONS="-vv 2>> /var/log/memcached/memcached.log -f 2 -n 32"
In this case -f 2 means that you will see 14 slabs and their chunk size doubles, -n is used to specify the minimum space allocated for key, value and flags.
Here are the result of our small test:
- Chunk details:
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM 3 320B 550s 1 113 yes 0 0 0 4 640B 681s 1 277 yes 0 0 0
- Memory usage:
total used free shared buffers cached Mem: 128 84 43 0 0 70 -/+ buffers/cache: 14 113 Swap: 0 0
Now you can compare it with our Memcached default configuration:
OPTIONS="-vv 2>> /var/log/memcached/memcached.log"
The results are:
- Chunk details:
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM 5 240B 765s 1 27 yes 0 0 0 6 304B 634s 1 93 yes 0 0 0 7 384B 634s 1 106 yes 0 0 0 8 480B 703s 1 133 yes 0 0 0 9 600B 634s 1 57 yes 0 0 0
- Memory usage:
total used free shared buffers cached Mem: 128 87 40 0 0 70 -/+ buffers/cache: 17 110 Swap: 0 0 0
You can also use -L to increase the memory page size in order to reduce the number of TLB misses and to improve the performance.
Thanks to this easy and straightforward optimization we can improve the usage of the allocated memory.
It can be very useful to take a deeper look into different systems. As you can see, they are much more complex than we can imagine. They consist of a number of methods, which can help to solve a variety of problems. Knowledge and understanding of the basics of each technology will help you in your development.