使用C语言实现内存池的示例代码

 更新时间:2024年02月06日 15:06:33   作者:yanghehuanglu  
所谓内存池,顾名思义和线程池的设计原理是一样的,为了减少频繁申请释放内存而带来的资源消耗,减少释放内存后产生的内存碎片,下面我们就来看看如何使用C语言实现内存池吧

概要

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

设计理念

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

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

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

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

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

模块设计

内存池结构

内存块节点结构

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;
}

到此这篇关于使用C语言实现内存池的示例代码的文章就介绍到这了,更多相关C语言实现内存池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中单调栈的基本性质介绍

    C++中单调栈的基本性质介绍

    这篇文章主要介绍了单调栈的基本性质介绍,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++中赋值运算符与逗号运算符的用法详解

    C++中赋值运算符与逗号运算符的用法详解

    这篇文章主要介绍了C++中赋值运算符与逗号运算符的用法详解,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 使用设计模式中的单例模式来实现C++的boost库

    使用设计模式中的单例模式来实现C++的boost库

    这篇文章主要介绍了使用设计模式中的单例模式来实现C++的boost库的方法,其中作者对线程安全格外强调,需要的朋友可以参考下
    2016-03-03
  • C语言中带头双向循环链表基本操作的实现详解

    C语言中带头双向循环链表基本操作的实现详解

    无头单向非循环链表结构简单,一般不会单独用来存数据。而带头双向循环链表的结构较为复杂,一般用在单独存储数据。本文将介绍带头双向循环链表的基本操作,需要的可以参考一下
    2022-11-11
  • C 语言的 printf() 函数全面解析

    C 语言的 printf() 函数全面解析

    printf()用于格式化输出到标准流,格式字符串包含转换说明(如%d、%f)和修饰符(宽度、精度、对齐等),支持多种数据类型及选项,但需注意类型转换规则与常见错误,如用%d输出浮点数会导致错误,本文给大家介绍C 语言的 printf() 函数的相关知识,感兴趣的朋友一起看看吧
    2025-09-09
  • 深入理解char *a与char a[]的区别

    深入理解char *a与char a[]的区别

    很多人可能或多或少知道char *a与char a[]的一些区别,但如果详细的说出来却不知如何说去,下面这篇文章就给大家详细介绍了关于C语言中char *a与char a[]的区别,有需要的朋友们可以参考借鉴,下面来一起学习学习吧。
    2016-12-12
  • C++利用SQLite实现命令行工具

    C++利用SQLite实现命令行工具

    这篇文章主要为大家详细介绍了一个基于 C++、SQLite 和 Boost 库的简单交互式数据库操作 Shell,该 Shell 允许用户通过命令行输入执行各种数据库操作,感兴趣的可以了解下
    2023-11-11
  • C++实现智能柜管理系统

    C++实现智能柜管理系统

    这篇文章主要为大家详细介绍了C++实现智能柜管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 搭建C语言开发环境(Windows平台)汇总

    搭建C语言开发环境(Windows平台)汇总

    本文给大家汇总了5种在WIN平台下搭建C语言开发环境的方法,包括一、在Windows平台配置GNU环境,二、使用Sublime Test开发C语言程序,三、使用VisualStudio开发C语言程序,四、搭建EclipseCDT集成开发环境,五、搭建Clion集成开发环境,有需要的小伙伴可以参考下
    2015-11-11
  • Qt实现屏幕底部冒泡效果

    Qt实现屏幕底部冒泡效果

    这篇文章主要为大家详细介绍了Qt实现屏幕底部冒泡效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08

最新评论