A simple memory allocation algrithim

来源:互联网 发布:傻黑的淘宝店 编辑:程序博客网 时间:2024/05/22 14:32



Purpose


Too frequent memory operation, such as malloc() and free(), can downgrade application performance. In order to improve the memory allocation performance, eliminate the impact of memory malloc() and free() operation, a customized memory allocation algorithm is introduced.


This algorithm  is not for suitable for large memory allocation environment.


Basics


The basic idea of this algorithm is to reduce the alloc/free times; so a large block of memory is pre-allocated, and when a memory malloc() is required from application, the memory will be allocated from these pre-allocated memory blocks.


To implement this algorithm, a memory block will be spitted into a few fixed-size slots; slots size is aligned with power of 2, for example: 32,64,128,256,512,1K,2K, and so on. The slot size of a same block is same, different block can have different slot size.


Free slots with same size are organized as a link; these slots may located in different blocks. A global variable is used to point to the header of this chain.

So when allocate request is coming, return the free header slot, and header move next; when free request is coming, put the return slot at the header, and adjust header pointer correspondingly.


All slots have fixed size and the size cannot be changed, and there is no split or merge operation on any slots.


When there is no free slot to use, a new memory block will be allocated, and immediately split into fixed-size slots, and put to the header.



And this is the detail slot structure:


API

/**

 * create a memory pool instance

 *

 * @param flag

 * @return memory pool pointer, used for mempool_alloc(void * pool, size_t size), and mempool_free(void * pool, void * ptr)

 */

void * mempool_new(unsigned int flag);


/**

 * alloc a memory space

 *

 * @param pool, the memory pool returned from a mempool_new

 * @param size, the memory size to be allocated, its value must be 1 <= size <= (1*1024*1024 - 16) bytes

 * @return memory pointer.

 */

void * mempool_alloc(void * pool, size_t size);



/**

 * free a memory block.

 *

 * @param pool, the memory pool returned from mempool_new

 * @param ptr, memory pointer to be freed, it must be a value returned from previous mempool_alloc call with same pool instance

 */

void mempool_free(void * pool, void * ptr);



Data Structure & Code

Compiled with gcc on Linux x86_64 platform.

Memory pool data structure

/** * MEMPOOL_MAGIC used to check this is a valid mempool instance. */#define MEMPOOL_MAGIC "MEMP"/** * Valid memory size [16=2**4, 1M=2**20] */#define MEMPOOL_MINSLOT 5#define MEMPOOL_MAXSLOT 20/** * forward declaration */static int find_slot_type(size_t size);/** * memorypool data structure */typedef struct {    char magic[4];                  // MEMPOOL_MAGIC    unsigned int id;                // random magic number    struct mem_slots_t {        void * freeslot;            // free slot links    } mem_slots[32];    unsigned int flag;              // flag} mem_pool_t;


mempool_new

/** * Create memory pool instance * * @return pool pointer, used for future alloc/free */void * mempool_new(unsigned int flag){    mem_pool_t * mempool = (mem_pool_t *)malloc(sizeof(mem_pool_t));    if (mempool == NULL)    {        D("ERROR: cannot allocate memory for memory pool.\n");        return NULL;    }    memset(mempool, 0, sizeof(mem_pool_t));    memcpy(mempool->magic, MEMPOOL_MAGIC, 4);    mempool->id = random();    mempool->flag = flag;    return mempool;}

mempool_alloc

void * mempool_alloc(void * pool, size_t size){    if (pool == NULL) return NULL;    mem_pool_t * mempool = (mem_pool_t *)pool;    if (memcmp((char *)(mempool->magic), MEMPOOL_MAGIC, 4) != 0)    {        D("ERROR: invalid memory pool pointer at 0x%x\n", pool);        return NULL;    }    // max memory size cannot exceed 1M Bytes.    int slottype = find_slot_type(size);    if (slottype < MEMPOOL_MINSLOT || slottype > MEMPOOL_MAXSLOT)    {        D("ERROR: allocate memory size (%d) is out of scope\n", size);        return NULL;    }    void * slot = NULL;    if (mempool->mem_slots[slottype].freeslot == NULL)    {        // there is no free slottype, alloc new memory block        size_t slotsize = 1 << slottype;        int pagesize = getpagesize();        size_t blocksize = slotsize <= pagesize ? pagesize : (slotsize <= 32*1024 ? 32*1024 : slotsize);        void * block = malloc(blocksize);        if (block == NULL)        {            D("ERROR: cannot allocate memory for memory block.\n");            return NULL;        }        D("INFO: allocate a new memory block size %d\n", blocksize);        // allocate slottype in the block        int i;        for (i = 0; i < blocksize/slotsize; i++)        {            slot = block + slotsize * i;            if (i != blocksize/slotsize - 1)                // set next slot                *(void **)slot = slot + slotsize;            else                *(void **)slot = mempool->mem_slots[slottype].freeslot;            *(unsigned int *)(slot + 8) = 0;                    // set size            *(unsigned int *)(slot + 12) = ~mempool->id;    // set free flag        }        mempool->mem_slots[slottype].freeslot = block;    }    // return the first slot in freeslot list    slot = mempool->mem_slots[slottype].freeslot;    *(unsigned int *)(slot + 8) = size;    *(unsigned int *)(slot + 12) = mempool->id;             // set busy flag    mempool->mem_slots[slottype].freeslot = *(void **)(mempool->mem_slots[slottype].freeslot);    return slot + 16;}

mempool_free

void mempool_free(void * pool, void * p){    if (pool == NULL || p == NULL) return;    mem_pool_t * mempool = (mem_pool_t *)pool;    if (memcmp((char *)(mempool->magic), MEMPOOL_MAGIC, 4) == 0)    {        if (*(unsigned int *)(p - 4) == mempool->id)        {            unsigned int size = * (unsigned int *)(p - 8);            int slottype = find_slot_type(size);            // put p back into freeslot list            *(void **)(p - 16) = mempool->mem_slots[slottype].freeslot;            *(unsigned int *)(p - 4) = ~mempool->id;            *(unsigned int *)(p - 8) = 0;            mempool->mem_slots[slottype].freeslot = p - 16;        }        else        {            D("ERROR: invalid memory pool magic at 0x%x\n", pool);        }    }    else    {        D("ERROR: invalid memory pool pointer at 0x%x\n", pool);    }}

TO DO NEXT

To support multi-threads environment.

To support memory block free operation.


0 0
原创粉丝点击