内存管理
概述
AliOS Things操作系统内核通过内存管理实现应用程序可以调用标准C库的malloc和free接口来动态的分配和释放内存。
内存管理函数
函数名 | 描述 |
aos_malloc() | 从系统heap分配内存给用户 |
aos_zalloc() | 从系统heap分配内存给用户,并且将分配的内存初始化为0 |
aos_calloc() | 从系统heap分配内存给用户,并且将分配的内存初始化为0 |
aos_realloc() | 重新调整之前调用 |
aos_free() | 内存释放函数 |
内存分配算法
AliOS Things内存管理采用类buddy伙伴算法,以及blk快速小内存申请算法相结合的策略。
buddy算法:
Buddy算法申请的内存最小为8字节对齐,可申请的最大长度除了受堆空间总大小限制外还可通过编译宏配置。系统提供的Buddy算法是通过32 bit的位图结构来挂载对应的空闲链表,bit n代表内存块对应的type,其下面挂载了长度范围 (2^(n- 1 + off) ~ 2^(n + off) - 1)的空闲块,其中off值主要是考虑利用了原本较小长度块的低bit。
内存申请时,优先从对应type的空闲链表中申请;如果没有空闲,则从 type+1 的位置申请内存,并将多余的空闲内存块做拆分并重新放入对应的空闲链表位置;每个内存块维测信息,包括如魔术字、多级申请调用栈、是否空闲等信息,便于内存踩踏、泄漏、重复释放等问题的定位。
内存释放时,考虑前后的内存块是否也空闲,如果是,则进行内存块合并,并插入相应type的空闲链表位置。 优点:能够满足绝大多数场景的内存申请需求; 可以申请最大范围内任意长度的内存; 内存碎片整理已经相当出色; 有充分的维测信息,便于问题定位。 缺点:内存维测信息较多,有一定的空间浪费; 内存不停地拆分组合,一定程度上影响效率; 长期运行过多的小内存会出现碎片,会隔断大内存空间。
blk小内存快速申请:
blk小内存算法申请的内存最小为4字节对齐,小于RHINO_CONFIG_MM_BLK_SIZE大小的内存块会优先从blk算法中申请,不够的再从通过buddy申请。
内存申请时,优先从对应type的空闲链表中申请;如果没有空闲,则先考虑从空闲资源池拉取一段空闲资源补充;如果空闲资源不足,则从 type+1 的位置申请内存(以此类推)申请过程不涉及拆分。
内存释放时,直接挂在到对应type的空闲链表内,释放不涉及合并。
优点:申请效率高; 避免过多小内存碎片。 缺点:内存维测信息少,出现问题较难定位; 申请的内存大小有限制,一般为1K以下。
常用配置
内存的常用配置都在各个单板的k_config.h中,如果不需修改,则会使用k_default_config.h里面的默认配置。当然由于其本身是宏定义,也可在board对应的YAML中定义。
打开关闭内存模块功能
def_config:
RHINO_CONFIG_MM_TLF: 1
打开关闭buddy内存模块的维测功能
def_config:
RHINO_CONFIG_MM_DEBUG: 1
内存维测打开时,记录内存申请时的多少级调用栈
def_config:
RHINO_CONFIG_MM_TRACE_LVL: 8
Buddy算法最大支持申请的内存大小bit位 实际大小换算为 1ul << RHINO_CONFIG_MM_MAXMSIZEBIT
def_config:
RHINO_CONFIG_MM_MAXMSIZEBIT: 28
打开关闭固定长度小内存块快速申请
def_config:
RHINO_CONFIG_MM_BLK: 1
固定长度小内存块总空间大小(byte)
def_config:
RHINO_CONFIG_MM_TLF_BLK_SIZE: 8192
设定从blk小内存申请的阈值(byte)即
def_config:
RHINO_CONFIG_MM_BLK_SIZE: 256
注:blk目前最大支持1K以下的小内存块如果需要调整可修改内部配置 MM_BLK_SLICE_BIT一般无需修改
API说明
使用示例
该示例可配置到helloworld_demo中运行,相关代码的下载、编译和固件烧录均依赖AliOS Things配套的开发工具 ,所以首先需要参考《AliOS Things集成开发环境使用说明之搭建开发环境》,下载安装 。 待开发环境搭建完成后,可以按照以下步骤进行示例的测试。
步骤1 创建或打开工程
打开已有工程
如果用于测试的案例工程已存在,可参考《AliOS Things集成开发环境使用说明之打开工程》打开已有工程。
创建新的工程
组件的示例代码可以通过编译链接到AliOS Things的任意案例(solution)来运行,这里选择helloworld_demo案例。helloworld_demo案例相关的源代码下载可参考《AliOS Things集成开发环境使用说明之创建工程》。
步骤2 添加组件
helloworld_demo组件的package.yaml中添加
depends:
- osal_aos: dev_aos # helloworld_demo中引入osal_aos组件
步骤3 下载组件
在已安装了的开发环境工具栏中,选择Terminal -> New Terminal启动终端,并且默认工作路径为当前工程的workspace,此时在终端命令行中输入:
aos install osal_aos
上述命令执行成功后,组件源码则被下载到了./components/osal_aos路径中。
步骤4 添加示例
osal_aos组件的package.yaml中添加example示例代码:
depends:
- rhino: dev_aos
- cli: dev_aos # 添加cli依赖
source_file:
- "*.c"
- "example/mem_example.c" # 添加 mem_example.c
步骤5 编译固件
在示例代码已经添加至组件的配置文件,并且helloworld_demo已添加了对该组件的依赖后,就可以编译helloworld_demo案例来生成固件了,具体编译方法可参考《AliOS Things集成开发环境使用说明之编译固件》。
步骤6 烧录固件
helloworld_demo案例的固件生成后,可参考《AliOS Things集成开发环境使用说明之烧录固件》来烧录固件。
步骤7 打开串口
固件烧录完成后,可以通过串口查看示例的运行结果,打开串口的具体方法可参考《AliOS Things集成开发环境使用说明之查看日志》。
当串口终端打开成功后,可在串口中输入help来查看已添加的测试命令。
步骤8 测试示例
CLI命令行输入:
mem_example
关键日志:
[aos_mem_example]aos_malloc success!
[aos_mem_example]aos_zalloc success!
[aos_mem_example]aos_calloc success!
[aos_mem_example]aos_realloc success!
注意事项
实际内存申请释放应统一通过malloc/free接口,其内部已经对接了aos_malloc/aos_free接口。
内存申请使用的堆统一由g_mm_region数据结构初始化(传入堆起点和长度),并在aos_init内核初始化接口中默认完成了内存模块的初始化。
FAQ
Q1: 内存模块的维测功能如何打开?
答:通过打开宏RHINO_CONFIG_MM_DEBUG即可打开内存管理模块的维测信息;其包含内存头魔术字、内存申请的调用栈以及当前内存空闲情况等等。 其中blk算法不包含维测信息。
Q2:如何查看当前内存的使用情况
答:通过在cli中输入 dumpsys_mm_info ,将所有内存块的使用情况,以及整体的占用空闲情况输出。