整理了一份通用的内存管理驱动代码

💡 原文中文,约2900字,阅读约需7分钟。
📝

内容提要

malloc是动态内存分配的一种方式,但容易出错,可能导致内存泄漏或崩溃。文章介绍了通用的内存管理驱动代码,包括内存池、内存管理表、内存管理参数和内存管理控制器结构体的定义。还介绍了重写的memcpy和memset函数以及常用的模块函数,如获取内存使用率、内存分配和释放内存。文章最后提到了良许教程网分享的Linux相关内容。

🔎

延伸解读

内存池与分块管理:从malloc到可控分配

文章没有直接使用标准malloc,而是通过预定义的内存池(内部SRAM、外部SDRAM、CCM)和内存管理表来管理内存。每个池被划分为固定大小的块,分配时搜索连续空闲块并返回偏移地址。这种方式将内存分配行为限制在已知区域,便于追踪使用情况,但块大小固定可能造成内部碎片,且分配效率受搜索算法影响。

重写memcpy/memset:为何要自己实现

作者重写了mymemcpy和mymemset,以字节为单位循环复制或设置内存。这可能是为了适配特定硬件或避免标准库依赖,但需注意:标准库函数通常经过优化,而简单循环在性能上可能不占优;此外,重写时需确保参数顺序和边界处理正确,否则可能引入新错误。文章未说明重写动机,读者应结合自身平台评估必要性。

使用率与分配释放:监控与风险点

my_mem_perused通过统计管理表中非零块计算使用率,返回千分比,便于监控内存压力。分配函数my_mem_malloc在未初始化时自动初始化,搜索连续空闲块,失败返回0xFFFFFFFF;释放函数my_mem_free根据偏移清除对应块。但文章未展示初始化函数和外部封装细节,且myrealloc中直接拷贝size字节可能超出旧内存实际大小,存在越界风险,实际使用需谨慎。

❓

Q&A

为什么嵌入式开发中要自己实现内存管理驱动,而不是直接用malloc?

malloc是动态内存分配的一种方式,但在嵌入式开发中容易出错或被忽略,例如忘记释放已分配的内存会导致内存泄漏或崩溃。因此作者整理了一份通用的内存管理驱动代码来避免这些问题。

这份内存管理驱动中定义了哪些内存池?它们分别位于哪里?

定义了三个内存池:mem1base为内部SRAM内存池;mem2base为外部SDRAM内存池,起始地址0XC01F4000,前面2M给LTDC用了;mem3base为内部CCM内存池,起始地址0X10000000。所有内存池都对齐到32字节。

内存管理表的作用是什么?如何定义?

内存管理表用于记录每个内存块是否被占用。定义方式为u32数组,例如mem1mapbase[MEM1_ALLOC_TABLE_SIZE]对应内部SRAM,mem2mapbase和mem3mapbase分别对应外部SDRAM和内部CCM,并指定了地址。

内存管理控制器结构体mallco_dev包含了哪些成员?

结构体_m_mallco_dev包含:内存初始化函数指针my_mem_init、内存使用率函数指针my_mem_perused、三个内存池基地址mem1base/mem2base/mem3base、三个内存管理状态表基地址mem1mapbase/mem2mapbase/mem3mapbase,以及三个内存管理未就绪标志(初始为0)。

my_mem_malloc函数是如何分配内存的?

my_mem_malloc首先检查内存管理是否就绪,未就绪则初始化;若size为0返回0XFFFFFFFF;然后计算需要的内存块数nmemb(向上取整);接着从内存管理表末尾向前搜索连续的空闲块,找到连续nmemb个空块后返回偏移地址(offset*memblksize[memx]),否则返回0XFFFFFFFF表示失败。

my_mem_free函数释放内存时有哪些返回值?分别代表什么?

my_mem_free返回u8类型:返回0表示释放成功;返回1表示内存管理未初始化(函数内会先执行初始化);返回2表示偏移地址超出范围(偏移超区)。

如何获取内存使用率?

通过my_mem_perused函数获取,它遍历指定内存池的管理表,统计被占用的块数used,然后返回(used*1000)/(memtblsize[memx]),即使用率(千分比形式)。

myrealloc函数是如何实现内存重新分配的?

myrealloc先调用my_mem_malloc分配新内存,若失败返回NULL;否则用mymemcpy将旧内存内容拷贝到新内存,再调用myfree释放旧内存,最后返回新内存首地址。

🏷️

标签

➡️

继续阅读