本文分析说明Zephyr的内存块分配器(Memory Blocks Allocator)机制。
Zephyr提供内存块分配器(Memory Blocks Allocator),通过该分配器可以从指定的内存区域动态分配到内存块:
- 同一个分配器中分配到的内存块大小都一样
- 可以同时分配和释放多个内存块
- 分配到一组的块可能不连续
- 管理区和内存区分离
和slab的区别, slab:
- 一次只能分配到一个slab
- 管理区在内存区中
内存块分配器
内存分配器实现在:
zephyr/include/zephyr/sys/mem_blocks.h
zephyr/lib/os/mem_blocks.c
定义内存分配器
由宏进行内存块内存分配的API有两个,都是通过定义全局变量申请的buf,管理器管理这些内部buf
1 | //定义一个名为name的内存分配器,block的大小为blk_sz, 总计有num_blks个block,内存按照buf_align对齐 |
以上两个宏都是由SYS_MEM_BLOCKS_DEFINE
实现,STATIC的mbmod使用staic修饰,可以看到定义了一个未初始的全局变量,大小为num_blks * WB_UP(blk_sz
1 | #define _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, balign, mbmod) \ |
由宏为内存块分配器指定外部内存的API有两个,管理器管理外部内存
1 | //定义一个名为name的内存分配器,block的大小为blk_sz, 总计有num_blks个block,block使用的内存由buf指定 |
4中定义内存块分配器的管理结构都是通过_SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF
定义, 创建一个Bitmap和sys_mem_blocks_t
1 | #define _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf, mbmod) \ |
分配内存块
sys_mem_blocks_alloc
分配的内存块之间可能不连续,sys_mem_blocks_alloc_contiguous
分配的内存块之间是连续的,实现如下
1 | int sys_mem_blocks_alloc(sys_mem_blocks_t *mem_block, size_t count, |
释放内存块
对应的sys_mem_blocks_free
用于释放非连续性的内存块,sys_mem_blocks_free_contiguous
用于释放连续性的内存块
1 | int sys_mem_blocks_free(sys_mem_blocks_t *mem_block, size_t count, void **in_blocks); |
调用的内部接口都是free_blocks
,只是sys_mem_blocks_free
每次都释放1个,而sys_mem_blocks_free_contiguous
释放全部,过程和分配对应这里就不列出代码分析了
释放分配内部函数
从前面分析可以看到释放和分配用alloc_blocks
和free_blocks
实现,块分配器使用bitmap进行管理,这里进行代码分析
1 | static void *alloc_blocks(sys_mem_blocks_t *mem_block, size_t num_blocks) |
强制分配
sys_mem_blocks_get
从指定的块地址in_block开始强制分配连续的count
个block,sys_mem_blocks_get
指定了要从哪个block开始分配,而sys_mem_blocks_alloc
则是由系统自行安排
1 | int sys_mem_blocks_get(sys_mem_blocks_t *mem_block, void *in_block, size_t count) |
检查block是否未分配
sys_mem_blocks_is_region_free
用于检查指定in_block
开始的count
个block是否未分配
1 | int sys_mem_blocks_is_region_free(sys_mem_blocks_t *mem_block, void *in_block, size_t count) |
多块分配器
Zephyr提供一个多块分配器将块分配器编为一个组,分配块时从这一组块分配器中按照注册的sys_multi_mem_blocks_choice_fn_t
选出块分配器进行分配。多块分配器使用下面结构体进行组织管理
1 | #define MAX_MULTI_ALLOCATORS 8 |
由于多块分配器的实现比较简单,下面就只说明API作用和实现方法
初始化多块分配器group
,注册块分配器选择函数choice_fn
, 主要是完成sys_multi_mem_blocks
内num_allocators
和choice_fn
的初始化
1 | void sys_multi_mem_blocks_init(sys_multi_mem_blocks_t *group, |
将堆分配器alloc
加入到多块分配器group
中,主要是修改num_allocators
,并将block信息拷贝进allocators
中
1 | void sys_multi_mem_blocks_add_allocator(sys_multi_mem_blocks_t *group, |
从多堆分配器group
中分配配置为cfg
,数量为count
的block, out_blocks
为分配到的block地址, blk_size
为分配到block的大小。
该函数调用choice_fn
选择器根据cfg
选择出堆分配器,再从分配器中分配连续的count
个block
1 | int sys_multi_mem_blocks_alloc(sys_multi_mem_blocks_t *group, |
释放in_blocks
开始连续count
个块回多堆管理器group中,该函数会先对比要释放的block属于allocators中的哪一个多堆分配器,再进行释放
1 | int sys_multi_mem_blocks_free(sys_multi_mem_blocks_t *group, |
参考
https://docs.zephyrproject.org/3.4.0/kernel/memory_management/index.html