news 2026/5/1 11:15:54

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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升级,证明这套静态内存池方案可用。上面说的后续我都会以博客的方式分享出来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 5:07:24

3步搞定复杂AI流程:可视化编排终极指南

3步搞定复杂AI流程&#xff1a;可视化编排终极指南 【免费下载链接】cube-studio cube studio开源云原生一站式机器学习/深度学习AI平台&#xff0c;支持sso登录&#xff0c;多租户/多项目组&#xff0c;数据资产对接&#xff0c;notebook在线开发&#xff0c;拖拉拽任务流pipe…

作者头像 李华
网站建设 2026/5/1 6:14:07

OctoSQL查询计划可视化终极指南:快速上手性能优化利器

OctoSQL作为一款强大的SQL查询引擎&#xff0c;能够对存储在多个数据库和文件格式中的数据进行统一查询。其核心功能之一就是查询计划可视化&#xff0c;通过--explain参数帮助用户深入理解查询执行流程&#xff0c;实现查询性能优化。无论是SQL初学者还是数据分析师&#xff0…

作者头像 李华
网站建设 2026/5/1 5:06:25

Cosmos-Server终极指南:打造最安全的家庭服务器解决方案

在数字化时代&#xff0c;数据安全和隐私保护已成为每个家庭用户的迫切需求。Cosmos-Server作为一款专为家庭用户设计的自托管服务器解决方案&#xff0c;为您提供企业级的安全防护和便捷的管理体验。 【免费下载链接】Cosmos-Server ☁️ The Most Secure and Easy Selfhosted…

作者头像 李华
网站建设 2026/5/1 10:11:18

5个步骤快速上手Transformer Lab开源项目:新手终极实战指南

5个步骤快速上手Transformer Lab开源项目&#xff1a;新手终极实战指南 【免费下载链接】transformerlab-app Experiment with Large Language Models 项目地址: https://gitcode.com/GitHub_Trending/tr/transformerlab-app Transformer Lab是一款强大的开源项目&#…

作者头像 李华
网站建设 2026/5/1 6:15:06

如何评估EmotiVoice生成语音的质量?专业指标解读

如何评估EmotiVoice生成语音的质量&#xff1f;专业指标解读 在虚拟偶像直播中突然“变脸”为冷漠机械音&#xff0c;或是导航播报用欢快语调念出交通事故提醒——这些令人出戏的瞬间&#xff0c;暴露出当前语音合成技术最核心的短板&#xff1a;缺乏对情感与个性的精准掌控。当…

作者头像 李华
网站建设 2026/4/16 15:31:46

节日祝福语音定制:EmotiVoice创意玩法

节日祝福语音定制&#xff1a;EmotiVoice创意玩法 在春节的钟声即将敲响时&#xff0c;一条来自孩子的语音祝福通过智能音箱播放&#xff1a;“爷爷奶奶&#xff0c;新年快乐&#xff01;”声音稚嫩又熟悉&#xff0c;仿佛就在耳边。可孩子远在千里之外求学——这并非录音&…

作者头像 李华