fmemory_pool.md 6.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

# 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:

-