# Memory pool
## 1. 概述
内存池 (Memory Pool)是一种内存分配方式,是为了减少频繁使用 malloc/free new/delete 等系统调用而造成的性能损耗而设计的,具有效率高、内存碎片少和防止内存泄漏等特性。内存池根据实际需要,在初始状态获取一大块内存(堆区或者静态内存),然后划分成若干内存页,进行管理,将内存页中的块传递给申请者使用。SDK中采用TLSF内存分配器管理,专门设计用于满足实时要求。
TLSF (Two-Level Segregated Fit memory allocator), 是一款通用的动态内存分配器,具有以下特点,
- malloc,free,realloc,memalign的算法复杂度变为O(1)
- 每次分配的开销极低(4字节)
- 低碎片化
- 支持动态添加和删除内存池区域
TLSF主要采用两级位图(Two-Level Bitmap)与分级空闲块链表(Segregated Free List)的数据结构管理动态内存池(memory pool)以及其中的空闲块(free blocks),用Good-Fit的策略进行分配。
TLSF算法分配速度不一定快,只是说能保证分配的时间是个常数(malloc不能保证)。
TLSF也叫多内存堆管理算法,支持动态增加或者删除多块不连续的内存,将它们作为一个内存堆使用。
## 2. 功能
FMemory Pool主要完成内存池的初始化,为用户提供多种内存申请方法,支持内存池的使用情况监测,
- 初始化内存池
- 删除内存池
- 申请一段空间(不要求对齐)
- 按指定字节数申请一段对齐的内存
- 申请一段数组,返回被清零的空间
- 回收原来申请的空间并重新分配
- 跟踪当前内存池的使用情况
相关源文件为:
```
fmempory_pool
├── fmempory_pool.c
└── fmempory_pool.h
```
```
tlsf
├── tlsf.c
└── tlsf.h
```
## 3. 配置方法
以下部分将指导您完成 FMemory Pool 的软件配置:
- 使能TLSF组件
## 4. 应用示例
### [memory pool](../../../baremetal/example/system/memory_pool_test)
## 5. API参考
### 5.1. 用户数据结构
- common/fmempory_pool.h
```c
typedef struct
{
pool_t pool_addr;
FSListNode list;
} FMempPoolList; /* 内存池控制数据 */
typedef struct
{
FMempPoolList *pools_list; /* 内存池链表 */
tlsf_t tlsf_ptr; /* tlsf内存池 */
u32 is_ready; /* 内存池初始化完成标志 */
} FMemp; /* 内存池控制数据 */
```
### 5.2 错误码定义
- 模块错误码编号 `0x0010000`
- [0x0] FMEMP_SUCCESS : success
- [0x0010000] FMEMP_ERR_INVALID_BUF : 输入的内存池缓存区不合法
- [0x0010001] FMEMP_ERR_INIT_TLFS : 初始化TLFS内存池失败
- [0x0010002] FMEMP_ERR_BAD_MALLOC : 从TLFS内存池分配空间失败
### 5.3. 用户API接口
#### FMempInit
- 初始化内存池, 分配内存池的内存空间
```c
FError FMempInit(FMemp *memp, void *begin_addr, void *end_addr);
```
Note:
- begin_addr end_addr 指向为内存池指定的缓冲区的起止地址
Input:
- {FMemp} *memp, 内存池的控制数据
- {void} *begin_addr, 分配给内存池的空间起始地址
- {void} *end_addr, 分配给内存池的空间结束地址
Return:
- {FError} FMEMP_SUCCESS表示初始化成功,返回其它值表示初始化失败
#### FMempRemove
- 释放所有分配的内存,删除内存池
```c
void FMempRemove(FMemp *memp);
```
Note:
- 需要初始化后才能调用,调用此函数后,内存池分配的空间不再能使用
Input:
- {FMemp} *memp 内存池控制数据
Return:
- 无
#### FMempMalloc
- 从内存池申请一段空间
```c
void *FMempMalloc(FMemp *memp, fsize_t nbytes);
```
Note:
- 需要初始化后才能调用,申请的空间再不再使用后需要调用FMempFree释放
Input:
- {FMemp} *memp 内存池控制数据
- {fsize_t} nbytes 申请的字节数
Return:
- {void *} 申请到的空间,如果申请失败,返回NULL
#### FMempCalloc
- 从内存池申请一段数组空间并清零
```c
void *FMempCalloc(FMemp *memp, fsize_t count, fsize_t size)
```
Note:
- 需要初始化后才能调用,申请的空间再不再使用后需要调用FMempFree释放
Input:
- {FMemp} *memp 内存池控制数据
- {fsize_t} count 数据成员格式
- {fsize_t} size 单个数据成员的字节数
Return:
- {void *} 申请到的空间,如果申请失败,返回NULL
#### FMempMallocAlign
- 按指定对齐方式申请一段空间
```c
void *FMempMallocAlign(FMemp *memp, fsize_t size, fsize_t align);
```
Note:
- 需要初始化后才能调用,申请的空间再不再使用后需要调用FMempFree释放
Input:
- {FMemp} *memp 内存池控制数据
- {fsize_t} size 申请的字节数
- {fsize_t} align 对齐字节数
Return:
- {void *} 申请到的空间,如果申请失败,返回NULL
#### FMempRealloc
- 回收原来申请的空间并重新分配
```c
void *FMempRealloc(FMemp *memp, void *ptr, fsize_t nbytes);
```
Note:
- 需要初始化后才能调用,申请的空间再不再使用后需要调用FMempFree释放,调用函数后,原来的空间不再能使用,原空间的数据被移动到返回指针指向的空间
Input:
- {FMemp} *memp 内存池控制数据
- {void} *ptr 原来的空间
- {fsize_t} nbytes 新申请的字节数
Return:
- {void *} 替换后空间,如果替换失败,返回NULL
#### FMempFree
- 释放一段从内存池申请的空间
```c
void FMempFree(FMemp *memp, void *ptr);
```
Note:
- 需要初始化后才能调用,传入的指针需要是FMempMalloc/FMempCalloc/FMempMallocAlign/FMempRealloc返回的
Input:
- {FMemp} *memp 内存池控制数据
- {void} *ptr 待释放的空间地址
Return:
- 无
#### FMemProbe
- 跟踪当前内存池的使用情况
```c
void FMemProbe(FMemp *memp, u32 *total, u32 *used, u32 *max_used);
```
Note:
- 需要初始化后才能调用
Input:
- {FMemp} *memp 内存池控制数据
- {u32} *total 总可用字节数
- {u32} *used 已使用字节数
- {u32} *max_used 已使用字节数的峰值
Return:
- 无
#### FMemListAll
- 打印当前分配的内存块信息
```c
void FMemListAll(FMemp *memp);
```
Note:
- 需要初始化后才能调用
Input:
- {FMemp} *memp 内存池控制数据
Return:
- 无