1

c语言实现内存池 - yanghehuanglu

 3 months ago
source link: https://www.cnblogs.com/yhfs/p/18009559
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

所谓内存池,顾名思义和线程池的设计原理是一样的,为了减少频繁申请释放内存而带来的资源消耗,减少释放内存后产生的内存碎片。

为了方便管理内存池的设计通常是划分出一定数量的内存块,这些内存块的长度是一样的; 用户申请内存块时返回空闲的内存块地址,如果内存块使用完毕就释放该内存块,将该内存块置为空闲状态,放回到内存池,供以后使用。

内存池的设计核心几大模块:创建内存池,申请内存块,释放内存块,销毁内存池!

当然这只是常用的内存池设计,实际项目中可以根据需求设计不同的线程池:内存块的长度不一,可以提供自定义的内存块设计等兼容性更高的内存池。

本文只做内存池原理的讲解和实现最基础的内存池!更多的功能根据实际的需求进行扩展即可。

内存池的设计思路有很多,可以给予链表,数组,队列等进行设计,核心就是怎么存储内存块信息;本期是基于链表进行的内存池设计。

内存池结构

内存块节点结构

typedef struct MemoryBlock{
    void *data;//内存块起始地址
    struct MemoryBlock *next;//下一个内存块的地址
}MemoryBlock;

内存池结构

typedef struct MemoryPool{
    MemoryBlock *freeList;//空闲内存块链表
    MemoryBlock *usedList;//占用内存块链表
    int freeCount;//空闲内存块数量
    int usedCount;//占用内存块数量
    int blockCount;//内存块总数量
}MemoryPool;

创建内存池

通过参数确定内存池中内存块的大小和数量,然后给每个内存块开辟空间,然后初始化空闲链表,占用链表,空闲数量,占用数量等

MemoryPool *InitMemoryPool(int blockSize, int blockCount)
{
    MemoryPool *pool = NULL;


    pool = (MemoryPool *)malloc(sizeof(MemoryPool));//为内存池分配空间
    pool->freeList = NULL;
    pool->usedList = NULL;
    for(int i = 0; i < blockCount; i++)
    {
        //创建内存块节点,插入到空闲链表
        MemoryBlock * block = (MemoryBlock *)malloc(sizeof(MemoryBlock));
        block->data = malloc(blockSize);
        block->next = pool->freeList;
        pool->freeList = block;
    }
    //初始化状态
    pool->freeCount = blockCount;
    pool->usedList = 0;
    pool->blockCount = blockCount;

    return pool;
}

申请内存块

将内存池中空闲的内存块提供给用户使用,如果没有空闲内存块返回NULL。

void *AllocateBlock(MemoryPool *pool)
{
    if(pool->freeList == NULL || pool->freeCount == 0)
        return NULL;
    MemoryBlock *node = pool->freeList;
    //该内存块从空闲链表删除
    pool->freeList = node->next;
    //该内存块插入到占用链表
    node->next = pool->usedList;
    pool->usedList = node;
    //更新空闲,占用状态
    pool->usedCount++;
    pool->freeCount--;

    return node->data;
}

释放内存块

将内存块放回到内存池

void FreeBlock(MemoryPool *pool, void *data)
{
    MemoryBlock *cur = pool->usedList;
    MemoryBlock *pre = NULL;

    //寻找给内存块的节点
    while(pre != NULL && cur->data != data)
    {
        pre = cur;
        cur = cur->next;
    }
    if(cur == NULL)
        return;
    //将该内存块从占用链表删除
    if(pre != NULL)
        pre->next = cur->next;
    else
        pool->usedList = cur->next;
    //将该内存块插入到空闲链表
    cur->next = pool->freeList;
    pool->freeList = cur;

    pool->freeCount++;
    pool->usedCount--;

   return;
}

销毁内存池

销毁所有的内存块及分配过的空间

void DestroyMemoryPool(MemoryPool *pool)
{
    MemoryBlock *pre = NULL;
    //释放所有空闲内存块空间
    while(pool->freeList != NULL)
    {
        pre = pool->freeList;
        free(pool->freeList->data);
        pool->freeList = pool->freeList->next;
        free(pre);
    }
    //释放所有占用内存块空间
    while(pool->usedList != NULL)
    {
        pre = pool->usedList;
        free(pool->usedList->data);
        pool->usedList = pool->usedList->next;
        free(pre);
    }
    //释放内存池空间
    free(pool);

    pool->freeList = NULL;
    pool->usedList = NULL;
    pool->freeCount = 0;
    pool->usedCount = 0;

    return;
}

至此一个最基础的内存池算是已经完成,在实际项目中可以在此基础上进行扩展;

main函数调用

int main(void)
{
    MemoryPool *pool;

    pool = InitMemoryPool(10, 5);

    int *str = (int *)AllocateBlock(pool);
    *str = 2;
    int *ptr = (int *)AllocateBlock(pool);
    *ptr = 3;
    printf("free block : %d, used block : %d\n", pool->freeCount, pool->usedCount);
    FreeBlock(pool, ptr);
    printf("free block : %d, used block : %d\n", pool->freeCount, pool->usedCount);

    DestroyMemoryPool(pool);

    return 0;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK