内存管理

更正文档

概述

AliOS Things操作系统内核通过内存管理实现应用程序可以调用标准C库的malloc和free接口来动态的分配和释放内存。

内存管理函数

函数名

描述

aos_malloc()

从系统heap分配内存给用户

aos_zalloc()

从系统heap分配内存给用户,并且将分配的内存初始化为0

aos_calloc()

从系统heap分配内存给用户,并且将分配的内存初始化为0

aos_realloc()

重新调整之前调用 aos_malloc(aos_calloc、aos_zalloc)所分配的内存块的大小

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 ,将所有内存块的使用情况,以及整体的占用空闲情况输出。