嘿,最近在折腾 ARM7 这种微控制器,突然发现一个超酷的内存管理库——umm_malloc。真心觉得,嵌入式里要搞点动态内存分配,用系统自带的 malloc/free 不仅大,而且不一定可用。umm_malloc 这家伙小巧、可靠,还专门针对 8/16/32 位芯片优化,简直是写裸机、RTOS、甚至大项目里管理一堆小对象的救星。
是什么
umm_malloc,全称 “Memory Manager For Small(ish) Microprocessors”。
– 纯 C 实现,几乎不依赖系统,直接把堆当成一个块数组来玩;
– 用 15 位 block 索引替代 32 位指针,头部开销只有 8 字节;
– 分配的块体只需 4 字节管理空间。
换句话说,整个管理模块不到十几 KB,开销超低,还能配置多个独立 heap。
解决了哪些问题和痛点
-
1. 嵌入式环境里系统堆可能不存在,或者没办法调试。
-
2. 大项目里想在一个进程中管理 N 个小对象,系统
malloc频繁碎片化; -
3. 资源受限平台,32 位指针链表太“奢侈”,内存头部开销大;
-
4. 想随时 dump heap、检查完整性、防写越界……系统库根本没有。
umm_malloc 就凭这些特性,把大部分痛点都对号入座、拿出来解决了。
主要 API 一览
|
函数 |
功能 |
void umm_init() |
在链接时根据符号初始化堆 |
void umm_init_heap(void *ptr, size_t size) |
运行时手动初始化堆 |
void *umm_malloc(size_t size) |
申请一块内存 |
void umm_free(void *ptr) |
释放内存 |
void *umm_realloc(void *ptr, size_t size) |
调整已分配块大小 |
如果你需要多堆管理,就用一套 umm_multi_* 接口,第一参数传 umm_heap*。很灵活。
代码示例
#include "umm_malloc_cfgport.h"
#include "umm_malloc.h"
// 链接时定义堆地址和大小
#define UMM_MALLOC_CFG_HEAP_ADDR my_heap_start
#define UMM_MALLOC_CFG_HEAP_SIZE (16*1024)
extern uint8_t my_heap_start[];// 在 linker script 里分配
int main(void){
umm_init();// 或者 umm_init_heap(ptr, size);
char *buf1 =(char*)umm_malloc(64);
if (buf1){
strcpy(buf1,"Hello, umm_malloc!");
printf("%s\n", buf1);
}
buf1 =(char*)umm_realloc(buf1,128);
umm_free(buf1);
return 0;
}
要启用更丰富的调试(dump、完整性检查、poison 检测),在 config 里打开 UMM_INFO、UMM_INTEGRITY_CHECK、UMM_POISON_CHECK,然后调用对应接口就行。
优缺点
|
优点 |
缺点 |
|
头部开销仅 8 字节,块对齐灵活 |
默认不带多线程/中断安全,需要自己加锁 |
|
用 block 索引替代指针,节省 50% 元数据空间 |
对齐、堆地址/大小要手动通过宏或 API 设置 |
|
支持多堆管理,API 同步,切换简单 |
不支持内置垃圾回收,只有基础 malloc/free |
|
可选开启 heap dump、完整性、边界溢出检测 |
适用于小内存场景,大堆时效率未必最佳 |
|
测试用例齐全,CMock + Ceedling 一键跑 |
需要一个 |
总结
好了,大致聊完了。umm_malloc 虽然算不上新概念,但把“嵌入式专用”做到了极致:最小化头部开销、简单可移植、测试驱动、多堆支持,还能按需打开各种调试选项。对比传统的 malloc/free,你会发现它更接地气、更透明,也更好调试。要是你的项目里真有动态分配需求,不妨拉下来折腾一下。
项目地址:https://github.com/rhempel/umm_malloc