当前位置: 首页 > news >正文

C语言实现一个简单的静态内存池

前提介绍

静态内存池的具体作用以及为什么要使用静态内存池就不做介绍,不清楚的博友可以网上找找介绍或者AI简单了解一下,这里的实现为固定大小的静态内存池,仅为我自己的一个想法,如果有更好的方法与实现逻辑可在评论区指正。

整体思路流程

假设有100个字节的大小,我需要按照10个字节为一块,一共10组。每次我做申请的时候我就只能获取其中一组,使用结束后释放又将其返回到之前容器里面。

这里的容器我打算使用链表的数据结构将其管理,10组数据我的链表结点就是10个(除开头结点),而链表本身也需要空间来存储,这里就需要使用malloc申请了吗?当然不是,以下就是我这个设计的妙点。

我这里的内存池空间是一个全局变量数组,它的生命周期是整个程序。当空闲块没有使用时,这块空间可以用来当作链表的结点,如下图:

这里的一个块空间大小是上面描述的10个字节,而每个结点则就只是一个指针,如果指针按照4字节大小的话,那么实际占用的空间就只是前4个字节,就必须保证每个块的大小至少为4个字节才能正常构建链表。

那么正常构建完成链表后就会是如下所示:

这样就把一个连续的全局变量数组构建成了一个链表。

此时,如果需要申请一块内存,就会使用头减的方式把head的下一个结点首地址分配出去,既分配结点1出去,然后把head的下一个结点指向结点2。

释放的方法和申请类似,使用头插的方式把释放的地址重新放入结点中。

示例流程:

部分代码实现

这里我实现了四个对应的API函数:

mem_pool_init:负责对这块全局变量内存进行链表化以及相关特征值的计算,并返回

相关handle等。

mem_pool_status_t mem_pool_init(stc_mem_pool_handle_t *handle, void *mem_pool, uint16_t mem_pool_size, uint16_t node_lenth) { if(handle == NULL || mem_pool == NULL || mem_pool_size == 0 || node_lenth == 0 || mem_pool_size%node_lenth != 0) { mem_pool_log("mem_pool_init error, handle is null or mem_pool is null or mem_pool_size is 0 or node_lenth is 0 or mem_pool_size mod node_lenth!= 0\n"); return MEM_POOL_PRARMETER_ERROR; } if(handle->is_init) { mem_pool_log("mem_pool_init error, handle is init\n"); return MEM_POOL_IS_INIT; } handle->list_head.next_node = NULL; handle->list_lenth = node_lenth; handle->crr_remaining_lenth = node_lenth; handle->mem_pool_size = mem_pool_size; handle->node_size = mem_pool_size/node_lenth; handle->is_init = 1; handle->mem_start_addr = (void *)mem_pool; //mem_pool_log("mem_pool start addr:%x, mem_pool_size:%d, node_lenth:%d, node_size:%d\n", handle->mem_start_addr, handle->mem_pool_size, handle->list_lenth, handle->node_size); uint16_t node_size = mem_pool_size/node_lenth; uint8_t *start_addr = (uint8_t *)mem_pool; mem_node_t *crr_node = &handle->list_head; for(int i = 0; i < handle->list_lenth; i++) { crr_node->next_node = (mem_node_t *)(start_addr + i * node_size); crr_node->next_node->next_node = NULL; crr_node = crr_node->next_node; } #if USE_RTOS_SYS mem_pool_mutex_init(handle->mutex); #endif return MEM_POOL_SUCCESS; }

mem_pool_deinit:销毁内存池对handle进行一些清空等。

mem_pool_status_t mem_pool_deinit(stc_mem_pool_handle_t *handle) { // 如果使用了rtos,可以使用一个临界区来保护内存池的初始化和释放 if(handle == NULL || handle->is_init == 0) { mem_pool_log("mem_pool_deinit error, handle is null or handle is not init\n"); return MEM_POOL_PRARMETER_ERROR; } handle->list_head.next_node = NULL; handle->crr_remaining_lenth = 0; handle->is_init = 0; handle->mem_pool_size = 0; handle->node_size = 0; handle->list_lenth = 0; handle->mem_start_addr = NULL; #if USE_RTOS_SYS mem_pool_mutex_deinit(handle->mutex); #endif return MEM_POOL_SUCCESS; }

mem_pool_alloc:通过传入handle申请内存空间。

void *mem_pool_alloc(stc_mem_pool_handle_t *handle) { if(handle == NULL || handle->is_init == 0) { mem_pool_log("mem_pool_alloc error, handle is null or handle is not init\n"); return NULL; } #if USE_RTOS_SYS MEM_POOL_MUTEX_LOCK(handle->mutex); #endif void *ret = NULL; mem_node_t *crr_node = handle->list_head.next_node; if(crr_node == NULL) { mem_pool_log("mem_pool_alloc error, crr_node is null\n"); return NULL; } ret = (void *)crr_node; handle->list_head.next_node = crr_node->next_node; handle->crr_remaining_lenth--; #if USE_RTOS_SYS MEM_POOL_MUTEX_UNLOCK(handle->mutex); #endif return ret; }

mem_pool_free:通过传入handle与释放地址做相关释放。

mem_pool_status_t mem_pool_free(stc_mem_pool_handle_t *handle, void *mem) { if(handle == NULL || mem == NULL) { mem_pool_log("mem_pool_free error, handle is null or handle is not init or mem is null\n"); return MEM_POOL_PRARMETER_ERROR; } if(handle->is_init == 0) { mem_pool_log("mem_pool_free error, handle is not init\n"); return MEM_POOL_IS_NOT_INIT; } uintptr_t mem_addr = (uintptr_t)mem; uintptr_t pool_start = (uintptr_t)(handle->mem_start_addr); uintptr_t pool_end = pool_start + handle->mem_pool_size; //if(mem < handle->mem_start_addr || mem >= (handle->mem_start_addr + handle->mem_pool_size)) { if(mem_addr < pool_start || mem_addr >= pool_end) { mem_pool_log("mem_pool_free error, mem is out of mem_pool\n"); return MEM_POOL_PRARMETER_ERROR; } //if((mem - handle->mem_start_addr) % handle->node_size != 0) { if((mem_addr - pool_start) % handle->node_size != 0) { mem_pool_log("mem_pool_free error, this not node addr\n"); return MEM_POOL_PRARMETER_ERROR; } #if USE_RTOS_SYS MEM_POOL_MUTEX_LOCK(handle->mutex); #endif memset(mem, 0, handle->node_size); mem_node_t *free_node = (mem_node_t *)mem; free_node->next_node = handle->list_head.next_node; handle->list_head.next_node = free_node; handle->crr_remaining_lenth++; #if USE_RTOS_SYS MEM_POOL_MUTEX_UNLOCK(handle->mutex); #endif return MEM_POOL_SUCCESS; }

示例应用

这里我写了一个简单的测试用例,使用260个字节全局变量,分成10个块,每个块空间占用26给字节。

#define TEST_MEM_POOL_NODE_LENTH (10) static uint8_t test_data[260]; static stc_mem_pool_handle_t test_handle; typedef struct { char name[10]; char number[11]; char sex[2]; char age[3]; long long c; } test_t; typedef struct { test_t va; int a; } cs; int main(void) { printf("%d,%d\n", sizeof(cs), sizeof(test_t)); mem_pool_init(&test_handle, test_data, sizeof(test_data), TEST_MEM_POOL_NODE_LENTH); test_node_info(&test_handle); test_t *xiao_m = (test_t *)mem_pool_alloc(&test_handle); if(xiao_m == NULL) { printf("mem_pool_alloc error %p\n", xiao_m); } test_t *xiao_h = (test_t *)mem_pool_alloc(&test_handle); if(xiao_h == NULL) { printf("mem_pool_alloc error %p\n", xiao_h); } test_t *xiao_l = (test_t *)mem_pool_alloc(&test_handle); if(xiao_l == NULL) { printf("mem_pool_alloc error %p\n", xiao_l); } printf("xiao_m: %p\n", xiao_m); printf("xiao_h: %p\n", xiao_h); printf("xiao_l: %p\n", xiao_l); memcpy(xiao_m->name, "xiao_m", sizeof("xiao_m")); memcpy(xiao_h->name, "xiao_h", sizeof("xiao_h")); memcpy(xiao_l->name, "xiao_l", sizeof("xiao_l")); memcpy(xiao_m->number, "10086", sizeof("10086")); memcpy(xiao_h->number, "1008611", sizeof("1008611")); memcpy(xiao_l->number, "10010", sizeof("10010")); memcpy(xiao_m->age, "20", sizeof("20")); memcpy(xiao_h->age, "19", sizeof("19")); memcpy(xiao_l->age, "18", sizeof("18")); memcpy(xiao_m->sex, "n", sizeof("n")); memcpy(xiao_h->sex, "n", sizeof("n")); memcpy(xiao_l->sex, "l", sizeof("l")); printf("xiao_m->name: %s\n", xiao_m->name); printf("xiao_h->name: %s\n", xiao_h->name); printf("xiao_l->name: %s\n", xiao_l->name); printf("xiao_m->number: %s\n", xiao_m->number); printf("xiao_h->number: %s\n", xiao_h->number); printf("xiao_l->number: %s\n", xiao_l->number); printf("xiao_m->sex: %s\n", xiao_m->sex); printf("xiao_h->sex: %s\n", xiao_h->sex); printf("xiao_l->sex: %s\n", xiao_l->sex); printf("xiao_m->age: %s\n", xiao_m->age); printf("xiao_h->age: %s\n", xiao_h->age); printf("xiao_l->age: %s\n", xiao_l->age); test_node_info(&test_handle); if(mem_pool_free(&test_handle, xiao_m) != MEM_POOL_SUCCESS) { printf("mem_pool_free error %p\n", xiao_m); } if(mem_pool_free(&test_handle, xiao_h) != MEM_POOL_SUCCESS) { printf("mem_pool_free error %p\n", xiao_h); } if(mem_pool_free(&test_handle, xiao_l) != MEM_POOL_SUCCESS) { printf("mem_pool_free error %p\n", xiao_l); } test_node_info(&test_handle); return 0; } void test_node_info(stc_mem_pool_handle_t *handle) { printf("\r\n"); mem_node_t *crr_node = handle->list_head.next_node; for(int i = 0; i < handle->crr_remaining_lenth; i++) { if(crr_node == NULL) { //printf("crr_node is null\n"); break; } printf("crr_addr:%p\n", crr_node); crr_node = crr_node->next_node; } }

后面还有释放后的链表打印,图太长了就不展示了。

最后,我使用我的这套静态内存池的方案自己写了一个AT指令驱动库,使用ESP8266 WIFI 模块做的例子。使用收发循环队列+静态内存池+UART DMA接收的方案做的,支持URC专用回调与注册,已经跑通了onenet的mqtt方案以及http ota升级,证明这套静态内存池方案可用。上面说的后续我都会以博客的方式分享出来。

http://www.cnnetsun.cn/news/118522.html

相关文章:

  • veScale:PyTorch原生大语言模型训练框架完整指南
  • Easy Effects终极音效配置指南:50+专业预设深度解析
  • 嵌入式Web服务器实战:STM32Cube与Mongoose完美融合
  • EmotiVoice语音抗噪能力测试:嘈杂环境可用性
  • 拒绝制造虚假情感依赖:产品设计准则
  • 推荐12个中英文降AIGC率工具,亲测有效!(含免费)
  • Taskflow:现代C++并行编程框架深度解析
  • Strapi无头CMS架构深度解析与现代化应用实践
  • 高效实现!分布式链路追踪:TraceIdFilter + MDC + Skywalking
  • EmotiVoice声音克隆功能实测:5秒样本还原度高达90%以上
  • AI服务热更新终极方案:零停机模型动态替换完整指南
  • 彻底告别语言障碍:Agent Zero多语言界面配置终极指南
  • 全国铁路货运站点分布图使用全攻略
  • AMD GPU终极指南:快速部署FlashAttention实现3-5倍AI加速
  • 从零开始掌握Stability AI视频生成:5步解决常见问题并提升效果
  • 只需3秒音频样本!EmotiVoice实现精准声音克隆
  • EmotiVoice日志分析:定位语音生成异常原因
  • Nacos配置推送失败的5个致命陷阱及终极修复方案
  • Sealos动态PVC管理终极指南:三步告别存储运维烦恼
  • 基于SpringBoot+Vue的滑雪场管理系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】
  • Java Web 短流量数据分析与可视化abo系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】
  • 【计算机毕业设计案例】基于springboot+微信小程序的DIY电脑推荐与交流平台DIY组装电脑踩坑,手残党DIY装机分享(程序+文档+讲解+定制)
  • Bazel终极指南:快速构建大规模多语言项目的完整解决方案
  • 终极Git文件管理指南:快速配置.gitattributes模板集合
  • 告别手绘流程图:Drawnix文本转图形黑科技全揭秘
  • 软件开发设计原则: 七大设计原则拯救面条代码
  • EmotiVoice用于虚拟主播直播的实时语音推流
  • Android ANR 深度起底:从系统埋雷机制到全链路治理体系
  • 2025提示工程实战手册:7天掌握AI对话优化核心技术
  • OpenWrt LuCI主题大比拼:4款官方界面哪个最适合你?