Skip to the content.

Software license Latest Release

MEMORY-POOL-ZERO (MPZ)

The MPZ is a simple implementation of a very fast and effective memory pool. It’s designed for using in applications with a lot of memory space allocations of the repeatedly sizes up to 1.024 bytes (default, configurable) per allocation, e.g. for structs in tokenization applications.

Features

Limitations

TODOs

Bugs

About MPZ

The MPZ implements memory space alignment to avoid wasting CPU cycles when accessing the data. The alignment is continuously implemented for the accessing internal metadata as well as for the return pointers to the user. The alignment size for memory space allocations from the OS is borrowed from GNU libc and is defined as 2 * sizeof(size_t) which is 16 bytes on 64 bit systems. By the way, the memory pool of nginx is one of the fastest pools today (as of year 2018) and it also uses this alignment, too. To allow a finer granulated usage of the memory space inside the MPZ, the MPZ implements binning of slots. The size of the memory space alignment for slots inside the MPZ is 8 bytes (default, configurable).

Pool

The pool is the main object of MPZ. It’s the owner of:

The size of a MPZ pool is 1.040 bytes on 64 bit systems.

Slabs

Every memory block allocated from the OS in MPZ is called slab. A slab consists of a small metadata (16 bytes on 64 bit systems) and of an 1-to-n number of slots, where n is defined as MPZ_SLAB_ALLOC_MUL constant (default 16, configurable).

Regular slots

Every chunk allocated from the pool in MPZ is called slot. A slot consists of a small metadata (32 bits for a header and 32 bits for a footer) and of a data part. The data part is the memory space that is returned to a user on an allocation request. The regular slots have a size of up to 1.024 bytes (default, configurable) and are managed by the bins-array of the pool.

Huge slots

In cases that the used needs memory space that is larger as the configurable default of 1.024 bytes, the MPZ will allocate an extra memory space from the OS and assign this space to a single slot in an extra slab. The differences to the regular slots are:

Illustrations

Illustration of a MPZ pool

SLABS (stack)

                                                 /
||============================================|| \ ||=====================||
||        slab 1       ||        slab 2       || / ||        slab n       ||
||                     ||                     || \ ||                     ||
||  metadata   | slots ||  metadata   | slots || / ||  metadata   | slots ||
||             |       ||             |       || \ ||             |       ||
|| prev | next | ..... || prev | next | ..... || / || prev | next | ..... ||
||===\======\==========/===/=======\==========|| \ ||==/=======\==========||
 \    \      \        /   /         \            /    /         \
  \    \      \      /   /           \          ...  /           \
   \  NULL     \____/   /             \________/   \/           NULL
    \__________________/


BINS (binning)

||===============================================================||
||     0 | ..... |     7 |     8 | ..... |    96 | ..... |   127 ||   <<< bin-index
||---------------------------------------------------------------||
||     8 | ..... |    64 |    72 | ..... |   776 | ..... |  1024 ||   <<< size in bytes per slot
||===============================================================||
     |               |                       |
     |               |                       |
 |=======|       |=======|               |=======|
 |       |       |       |               |       |
 |=======|       |=======|               |=======|
                     |                       |
                     |                       |                        <<< free slots
                 |=======|               |=======|
                 |       |               |       |
                 |=======|               |=======|
                     |
                     |
                 |=======|
                 |       |
                 |=======|

Illustration of the regular MPZ slots inside the bins-list

               slot from slab x                                      slot from slab y
                                                   /
||==============================================|| \ ||==============================================||
||  header   |   data part   |  footer   |      || / ||  header   |   data part   |  footer   |      ||
||           |               |           |      || \ ||           |               |           |      ||
|| (32 bits) | (min 8 bytes) | (32 bits) | next || / || (32 bits) | (min 8 bytes) | (32 bits) | next ||
||===========================================\==|| \ ||===========================================\==||
                                              \    / /                                             \
                                               \____/                                             NULL

Illustration of a MPZ slot header

The header contains the metadata of the slot. All of the 32 bits of the footer a filled with 1. This fact allows to detect segmentation fault errors if an application writes over the allocated memory space (unreliable but simple).

=======
|  31 |   <<< "huge" flag (MSB on little-endian machines)
-------
|  30 |   <<< "used" flag (allows to detect "double free" errors)
-------
|  29 |   <<< currently unused (reserved for possible extensions)
-------
|  28 |\
------- \
| ... |   <<< represent the slot size
------- /
|   0 |/  (LSB on little-endian machines)
=======

MPZ API

mpz_pool_create()

Allocates an aligned memory space for the pool, initializes the allocated memory space to zero and returns a pointer to the pool object. Returns NULL if failed.

mpz_pool_t *mpz_pool_create(mpz_void_t);

mpz_pool_reset()

Resets the allocated memory space to permitt him to be efficiently reused by the pool. Note that the memory space of huge slots is immediately released back to the OS.

mpz_void_t mpz_pool_reset(mpz_pool_t *pool);

mpz_pool_destroy()

Destroys the pool. The total allocated memory space inclusive the memory space of the pool itself is released back to the OS.

mpz_void_t mpz_pool_destroy(mpz_pool_t *pool);

mpz_pmalloc()

Allocates size bytes of the memory space from the pool. If the requested size is greater than the configurable default of 1.024 bytes, a huge slot is directly allocated from the OS like described above in the section Huge slots. If the pool hasn’t enouth free memory space to serve the requested size of bytes, a new slab is allocated from the OS. Returns NULL if failed.

mpz_void_t *mpz_pmalloc(mpz_pool_t *pool, mpz_csize_t size);

mpz_pcalloc()

Allocates size bytes of the memory space from the pool like mpz_pmalloc() function. Additionaly, all bits of the allocated memory space are initialized with zero. Returns NULL if failed.

Note that the `mpz_pcalloc()` function is always slower than the `mpz_pmalloc()`,
because the initializing of the bits in the memory space with zero requires an extra
iteration over the requested memory space.
mpz_void_t *mpz_pcalloc(mpz_pool_t *pool, mpz_csize_t size);

mpz_free()

Releases the allocated memory space back to the pool. The memory space of huge slots are immediately released back to the OS.

mpz_void_t mpz_free(mpz_pool_t *pool, mpz_void_t *data);

Using MPZ

The user should use the MPZ API. The direct usage of functions outside the MPZ-API can lead to unpredictable consequences if there is a lack of knowledge about the internal implementation. To modify or extend the MPZ see the description FOR DEVELOPER WHO WANT TO ADAPT THE MPZ TO THE REQUIREMENTS OF THEIR APPLICATIONS in the mpz_core.h.

The MPZ should be used wisely. Note that the MPZ is a high-level application. It’s a simple interface between the user and the malloc() and the free() functions. The MPZ doesn’t interact with the OS directly. Any invalid read/write errors are difficultly to detect than using malloc() function directly. For example, many users forget to allocate an extra byte to terminate a string with a \0 byte. Here is a big difference between the allocation of memory space from the malloc() function and the MPZ. If the user allocates 5 bytes of memory space from the MPZ to write a Hello string into the allocated memory space, the MPZ provides at least 8 bytes of the memory space, where, by contrast, the malloc() function would provide only 5 bytes of really usable memory space. The invalid writing of the final 0-byte could easy be detected by the direct usage of the malloc() function. Using the MPZ, this error wouldn’t be detected.

Example

#include "mpz_alloc.h"

int example_function()
{
    mpz_pool_t  *pool;
    void        *data;

    pool = mpz_pool_create();

    if (NULL == pool) {
        return 1;
    }

    data = mpz_pmalloc(pool, 123);

    if (NULL == data) {
        mpz_pool_destroy(pool);

        return 1;
    }

    /* Do here something with the "data"... */

    mpz_free(pool, data);

    /* Do other operations with the pool... */

    mpz_pool_destroy(pool);

    return 0;
}