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语言可以使用alloc从栈上动态分配内存. 内存碎片 Malloc/free或者new/delete大量使用会造成内存碎片,这种碎片形成的机理如下: 内存碎片一般是由于空闲的内存空间比要连续申请的空 ...
- linux下C语言实现的内存池【转】
转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html 操作系统:ubuntu10.04 前言: 在通信过程中,无法知道将会接收到的 ...
- 高效内存池的设计方案[c语言]
一.前言概述 本人在转发的博文<内存池的设计和实现>中,详细阐述了系统默认内存分配函数malloc/free的缺点,以及进行内存池设计的原因,在此不再赘述.通过对Nginx内存池以及< ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- JVM内存管理------JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- 【uTenux实验】内存池管理(固定内存池和可变内存池)
1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...
- 对象池与.net—从一个内存池实现说起
本来想写篇关于System.Collections.Immutable中提供的ImmutableList里一些实现细节来着,结果一时想不起来源码在哪里--为什么会变成这样呢--第一次有了想写分析的源码 ...
- loki之内存池SmallObj[原创]
loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板 ...
- JVM内存管理之JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- Boost内存池使用与测试
目录 Boost内存池使用与测试 什么是内存池 内存池的应用场景 安装 内存池的特征 无内存泄露 申请的内存数组没有被填充 任何数组内存块的位置都和使用operator new[]分配的内存块位置一致 ...
随机推荐
- 【调试】sysRq按键使用方法
SysRq键简介 SysRq键是一个魔术案件,只要在内核没有完全卡死的情况下,内核都会相应SysRq 键的输入,使用这些组合键都可以搜集包括系统内存使用.CPU任务处理.进程运行状态等系统运行信息. ...
- prettier配置项说明
Prettier 特点 一键改变代码风格,无需改变开发风格 => 1. 安装Node 环境 自行安装 => 2. 安装 Prettier 全局安装npm install --global ...
- sql语句内变量的使用
0.原始表格如下: 1.定义变量,并在sql语句内查询: set @user_name = "成龙";SELECT * FROM `tb_user` where userName ...
- P1914 小书童——凯撒密码
1.题目介绍 小书童--凯撒密码 题目背景 某蒟蒻迷上了 "小书童",有一天登陆时忘记密码了(他没绑定邮箱 or 手机),于是便把问题抛给了神犇你. 题目描述 蒟蒻虽然忘记密码,但 ...
- [转帖]Java 提速之 Large pages【译】
https://juejin.cn/post/7011002046899978253 一.前言 最近花了很多时间在 JVM 的内存预留代码上.它开始是因为我们得到了外部贡献,以支持在 Linux 上使 ...
- [转帖]oracle OSWatcher安装部署
Oswatch是oracle官方提供,用于收集操作系统性能的小工具,oswatch的安装与使用也比较简单,直接解压就可以使用.oswatch是通过调用系统的命令完成信息的收集,如:ps ,top ,m ...
- 【转帖】PyCharm---Django简单例子--基础1
https://www.cnblogs.com/kllay/p/7286701.html 环境: python 2.7 Django 1.11.2 查看版本:python -m django - ...
- [转帖]SystemStap、BCC、bpftrace
https://plantegg.github.io/2019/09/16/SystemStap/ Linux 4.4+ 支持 eBPF.基于 eBPF 可以将任何内核函数调用转换成可带任何 数据的用 ...
- java浅拷贝BeanUtils.copyProperties引发的RPC异常 | 京东物流技术团队
背景 近期参与了一个攻坚项目,前期因为其他流程原因,测试时间已经耽搁了好几天了,本以为已经解决了卡点,后续流程应该顺顺利利的,没想到 人在地铁上,bug从咚咚来~ 没有任何修改的服务接口,抛出异常: ...
- [LeetCode刷题记录]39 组合总和
题目描述 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合.candidates 中的数字可以无限制 ...