首页 > 系统相关 >c语言实现内存池

c语言实现内存池

时间:2024-02-06 13:22:07浏览次数:26  
标签:usedList 语言 实现 内存 freeList NULL pool MemoryBlock

概要

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

设计理念

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

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

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

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

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

模块设计

内存池结构

内存块节点结构

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

 

标签:usedList,语言,实现,内存,freeList,NULL,pool,MemoryBlock
From: https://www.cnblogs.com/yhfs/p/18009559

相关文章

  • 索引构建磁盘IO太高,巧用tmpfs让内存来帮忙
    在文本索引构建这种需要大量占用磁盘IO的任务,如果正巧你的内存还有点余粮,是否可以先索引存储到内存,然后再顺序写入到磁盘呢?,需要大量占用磁盘IO,如果正巧你的内存还有点余粮,是否可以先索引存储到内存,然后再顺序写入到磁盘呢?将Linux的内存变为磁盘,可以通过tmpfs文件系统实现。tmpf......
  • vue 导出多页pdf, window.print()实现
    如果你对分页打印没思路,而网上的现成方案又不适合,不妨进来看看,也许会对你有帮助.由于工作环境是局域网,对于插件的安装有限制,所以排除了jspdf+html2canvas的实现方式;采用window.print(),就会涉及到表格的截断、文本的截断等问题,而且需求要求每一页的pdf都有固定的页眉页尾,这里好......
  • CRM管理系统针对客户跟进有哪些功能?如何实现精准跟进客户?
      客户跟进是任何成功企业的命脉,它是从初始联系到转化、从培育到购买之间的桥梁。然而,客户们每天都被各种信息轰炸,很难将注意力集中在任何一个事情上。因此,企业想要在客户中脱颖而出,就必须能够吸引并维持他们的注意力。CRM管理系统应运而生,它能赋予各种规模的企业构建个性化、......
  • Canvas实现音频可视化波形图
    @目录1.效果演示2.基本概念说明2.1音频源节点2.2时域图2.3频谱图3.案例代码1.效果演示上图演示了音频的波形随着音乐的节奏而跌宕起伏2.基本概念说明2.1音频源节点音频数据的来源,是音频处理的其中一个环节2.2时域图声音信号是一维的时域信号,无法观察出频......
  • nodejs中实现sm4加解密
    SM4是中国密码局颁布的一种分组密码算法,也称为国密SM4。它是基于对称密钥加密算法的一种分组密码算法,具有较高的安全性和较快的加密速度。SM4使用128位的密钥和128位的分组进行加密。sm-crypto是一个支持国密SM2、SM3、SM4等算法的Node.js加密库。要使用sm-crypto库......
  • vue2中el-tree组件实现双击树的节点来修改节点名称
    目标在没双击之前,树的节点是文本样式。在双击之后,节点位置变成输入框形式,原节点的名称显示在输入框中,可以进行修改。修改完毕之后,当输入框失去焦点的时候,输入框消失,又变成原本的文本样式,并且显示的是修改后的节点名称。添加一个树<template><div><el-tree......
  • java实现导出mysql数据库表信息
    java实现导出mysql数据库表信息,导出信息包含:数据库用户名,表英文名,表中文名,表业务描述,字段数量等等packagesrc.main.biz.ucenter.utils;importorg.apache.poi.ss.usermodel.Row;importorg.apache.poi.ss.usermodel.Sheet;importorg.apache.poi.ss.usermodel.Workbook;impor......
  • C语言-calloc
    #include<stdio.h>#include<stdlib.h>intmain(){int*p=(int*)calloc(10,sizeof(int));if(p==NULL){perror("calloc");exit;}printf("%d\n",&p);//6487576printf("%......
  • 借助CRM实现高效线索管理,助力企业拿下订单!
    随着“以客户为中心”观念的逐渐普及,销售团队的客户比过去更复杂,交易周期更久,竞争也更激烈。假如没有明确的销售计划,团队可能陷入混乱,最后导致客户&公司之间的负面结果。在这种情况下,人工智能驱动的CRM管理系统成为了销售团队维持高效管理线索的有效途径。CRM线索管理如何帮助企......
  • Linux 中实现去重复后仍然按照原来的顺序输出
     001、一般去重复[root@PC1test01]#lsa.txt[root@PC1test01]#cata.txt##测试文本cdcabb[root@PC1test01]#cata.txt|sort|uniq##去重复后也排序了abcd 002、去重复后保持原来的顺序[root@PC1test01]#lsa......