C语言实现内存池

转自:http://blog.csdn.net/szkbsgy/article/details/50491216,我根据自己情况做了部分修改。

在编程中,为了避免由于频繁的malloc/free产生内存碎片,通常会在程序中实现自己的内存管理模块,即内存池。内存池的原理:程序启动时为内存池申请一块较大的内存,在程序中使用内存时,都由内存池进行分配,不再使用的内存交给内存池回收,用于再次分配。内存池一般会有如下的接口:memory_pool_init, memory_pool_malloc, memory_pool_free 和 memory_pool_destroy。本文实现了一个简单的内存池,仅用于基础学习。

memory_pool.h

#ifndef __MEMORY_POOL_H__
#define __MEMORY_POOL_H__

#define MAX_POOL_SIZE 1024 * 1024
#define BLOCK_SIZE 16

typedef struct memory_map_talbe
{
    char *p_block;
    int used;
} Memory_Map_Table;

typedef struct memory_alloc_table
{
    char *p_start;
    int used;
    int block_start_index;
    int block_cnt;
}Memory_Alloc_Table;

typedef struct memory_pool
{
    char *memory_start;//内存池起始地址, free整个内存池时使用
    Memory_Alloc_Table *alloc_table;
    Memory_Map_Table *map_table;
    int total_size;
    int internal_total_size;
    int used_size;
    int block_size;
    int block_cnt;
    int alloc_cnt;
} Memory_Pool;

extern Memory_Pool *memory_pool_init(int size);
extern void *Memory_malloc(Memory_Pool *pool, int size);
extern void memory_free(Memory_Pool *pool, void *memory);
extern void memory_pool_destroy(Memory_Pool *pool);

#endif

memroy_pool.c

#include 
#include 
#include 
#include "memory_pool.h"

//获取内存映射表的位置
Memory_Map_Table *map_table_pos(Memory_Pool *pool)
{
    Memory_Map_Table *p = (Memory_Map_Table *)(pool->memory_start + sizeof(Memory_Pool));
    return p;
}

//获取内存分配表的位置
Memory_Alloc_Table *alloc_talbe_pos(Memory_Pool *pool)
{
    Memory_Alloc_Table *p = (Memory_Alloc_Table *)(pool->memory_start + sizeof(Memory_Pool) +
            sizeof(Memory_Map_Table) * (pool->block_cnt));
    return p;
}


//获得memory在位置
char *memory_pos(Memory_Pool *pool)
{
    char *p = (char *)(pool->memory_start + sizeof(Memory_Pool) +
            (sizeof(Memory_Map_Table) + sizeof(Memory_Alloc_Table))* pool->block_cnt);
    return p;
}

Memory_Pool *memory_pool_init(int size)
{
    char *p = NULL;
    char *p_memory = NULL;
    Memory_Pool *pool = NULL;
    Memory_Alloc_Table *alloc_table = NULL;
    Memory_Alloc_Table *p_alloc_table = NULL;
    Memory_Map_Table *map_table = NULL;
    Memory_Map_Table *p_map_table = NULL;
    int block_cnt = 0;
    int all_size = 0;
    int i = 0;

    if (size < 0 || size > MAX_POOL_SIZE) {
        printf("memory_pool_init(): Invalid size(%d)\n", size);
        return pool;
    }

    block_cnt = ((size + BLOCK_SIZE - 1) / BLOCK_SIZE);
    all_size = sizeof(Memory_Pool) + (sizeof(Memory_Map_Table) +
            sizeof(Memory_Alloc_Table)) * block_cnt + size;
    p = (char *)malloc(all_size);
    if (p == NULL) {
        perror("Malloc failed\n");
        return pool;
    }

    memset(p, 0, all_size);

    pool = (Memory_Pool *)p;
    pool->block_cnt = block_cnt;
    pool->block_size = BLOCK_SIZE;
    pool->internal_total_size = BLOCK_SIZE * block_cnt;
    pool->total_size = size;
    pool->used_size = 0;
    pool->alloc_cnt = 0;
    pool->memory_start = p;

    p_memory = memory_pos(pool);
    map_table = map_table_pos(pool);
    for (i = 0; i < block_cnt; i++) {
        p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
        p_map_table->p_block = p_memory + i * BLOCK_SIZE;
        p_map_table->used = 0;
    }

    alloc_table = alloc_talbe_pos(pool);
    for (i = 0; i < block_cnt; i++) {
        p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
        p_alloc_table->block_cnt = 0;
        p_alloc_table->block_start_index = -1;
        p_alloc_table->p_start = NULL;
        p_alloc_table->used = 0;
    }

    printf("memory_pool_init: total size: %d, block cnt: %d, block size: %d\n",
            pool->total_size, pool->block_cnt, BLOCK_SIZE);
    return pool;
}

void *Memory_malloc(Memory_Pool *pool, int size)
{
    char *p_start = NULL;
    int need_block_cnt = 0;
    Memory_Map_Table *map_table = NULL;
    Memory_Map_Table *p_map_table = NULL;
    Memory_Alloc_Table *alloc_table = NULL;
    Memory_Alloc_Table *p_alloc_table = NULL;
    int block_cnt = 0;
    int start_index = -1;
    int i = 0;

    if (size <= 0) {
        printf("Invalid size(%d)\n", size);
        return p_start;
    }

    if (size > pool->total_size) {
        printf("%d is more than total size\n", size);
        return p_start;
    }

    if (size > pool->total_size - pool->used_size) {
        printf("Free memory(%d) is less than allocate(%d)\n",
        pool->total_size - pool->used_size, size);
        return NULL;
    }

    need_block_cnt = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
    map_table = map_table_pos(pool);

    start_index = -1;
    for (i = 0; i < pool->block_cnt; i++) {
        p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
        if (p_map_table->used) {
            //printf("before alloc: map index: %d is used\n", i);
            block_cnt = 0;
            start_index = -1;
            continue;
        }

        if (start_index == -1) {
            start_index = i;
            //printf("start_index: %d\n", start_index);
        }

        block_cnt++;

        if (block_cnt == need_block_cnt) {
            break;
        }
    }

    if (start_index == -1) {
        printf("No available memory to used\n");
        return NULL;
    }

    alloc_table = alloc_talbe_pos(pool);

    for (i = 0; i < pool->block_cnt; i++) {
        p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
        if (p_alloc_table->used == 0) {
            break;
        }

        p_alloc_table = NULL;
    }

    if (p_alloc_table == NULL) {
        return NULL;
    }

    p_map_table = (Memory_Map_Table *)((char *)map_table + sizeof(Memory_Map_Table) * start_index);
    p_alloc_table->p_start = p_map_table->p_block;
    p_alloc_table->block_start_index = start_index;
    p_alloc_table->block_cnt = block_cnt;
    p_alloc_table->used = 1;

    for (i = start_index; i < start_index + block_cnt; i++) {
        p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
        //printf("map index: %d is used\n", i);
        p_map_table->used = 1;
    }

    printf("Alloc size: %d, Block: (start: %d, end: %d, cnt: %d)\n", size,
            start_index, start_index + block_cnt - 1, block_cnt);
    pool->alloc_cnt++;
    pool->used_size += size;
    return p_alloc_table->p_start;
}

void memory_free(Memory_Pool *pool, void *memory)
{
    Memory_Map_Table *map_table = NULL;
    Memory_Map_Table *p_map_table = NULL;
    Memory_Alloc_Table *alloc_table = NULL;
    Memory_Alloc_Table *p_alloc_table = NULL;
    int i = 0;
    int block_start_index = 0;
    int block_cnt = 0;

    if (memory == NULL) {
        printf("memory_free(): memory is NULL\n");
        return;
    }

    if (pool == NULL) {
        printf("Pool is NULL\n");
        return;
    }

    alloc_table = alloc_talbe_pos(pool);

    for (i = 0; i < pool->alloc_cnt; i++) {
        p_alloc_table = (Memory_Alloc_Table *)((char *)(alloc_table) + i * sizeof(Memory_Alloc_Table));
        if (p_alloc_table->p_start == memory) {
            block_start_index = p_alloc_table->block_start_index;
            block_cnt = p_alloc_table->block_cnt;
            break;//add by wangk
        }
    }

    if (block_cnt == 0) {
        return;
    }

    map_table = map_table_pos(pool);

    printf("Block: free: start: %d, end: %d, cnt: %d\n", block_start_index,
            block_start_index + block_cnt -1, block_cnt);

    for (i = block_start_index; i < block_start_index + block_cnt; i++) {
        p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
        p_map_table->used = 0;

        printf("block:%d, no used\n", i);
    }

    p_alloc_table->used = 0;
    pool->used_size -= block_cnt * BLOCK_SIZE;
}

void memory_pool_destroy(Memory_Pool *pool)
{
    if (pool == NULL) {
        printf("memory_pool_destroy: pool is NULL\n");
        return;
    }

    free(pool);
    pool = NULL;
}

main.c

#include 
#include "memory_pool.h"

#define if_mem_is_null(pool, ptr) do{\
            if(ptr != NULL) \
                memory_free(pool, ptr);\
        }while(0);

int main(void)
{
    Memory_Pool *pool = NULL;
    char *p1 = NULL;
    char *p2 = NULL;
    char *p3 = NULL;
    char *p4 = NULL;
    int i = 0;

    pool = memory_pool_init(1024);
    if (pool == NULL)
        printf("memory pool init failed\n");

    p1 = (char *)Memory_malloc(pool, 64);
    if (p1 == NULL)
        printf("p1,Malloc failed\n");
    else
        printf("p1,malloc success\n");

    p2 = (char *)Memory_malloc(pool, 32);
    if (p2 == NULL)
        printf("p2, Malloc failed\n");
    else
        printf("p2, Malloc success\n");

    p3 = (char *)Memory_malloc(pool, 128);
    if (p3 == NULL)
        printf("p3, Malloc failed\n");
    else
        printf("p3, Malloc success\n");

    if_mem_is_null(pool, p2);

    p4 = (char *)Memory_malloc(pool, 96);
    if (p4 == NULL)
        printf("p4, Malloc failed\n");
    else
        printf("p4, Malloc success\n");

    memory_pool_destroy(pool);

    return 0;
}

Memory_Pool: 用于内存属性结构,用于整个内存池的管理

Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory

Memory_Alloc_Table: 内存分配表,用于记录分配过的内存

Memory:实际用于分配的内存


说明:内存的分配是以块为单位的,向上取整,不足一块的按一块处理。

缺点:

1.  实际的可分配内存只是内存池中Memory表示的结构,其它的结构都是内存池管理用的,会造成内存浪费,而且是内存池越大,管理结构越大,浪费内存越多

2. 如果块大小设为64B, 而申请1B,会造成63B的浪费,所以申请内存最好是块大小的整数倍。

3.  当无内存可分配时,内存池不会自动增长




你可能感兴趣的:(IT技能)