RT_Thread内核源码分析(五)——内存管理@小堆内存管理算法

目录

1、内存堆控制

         1.1 内存堆控制器   

1.2 内存块节点

1.3 内存堆管理

2、内存堆初始化

2.1 初始化接口

2.2 初始化示例

2.3 源码分析

3、内存堆操作

3.1 内存块申请

3.1.1 相关接口

3.1.2 原理分析

3.1.3 示例分析

3.1.4 代码分析

3.2 内存块伸缩

3.2.1 相关接口

3.2.2 原理分析

3.2.3 示例分析

3.2.4 源码分析

3.3 内存快释放

3.3.1 相关接口

3.3.2 原理分析

3.3.3 示例分析

3.3.4 源码分析


   本章讲解RT_Thread Nano实时操作系统的动态内存(内存堆)部分,RT-Thread提供三种动态内存管理算法:小堆内存管理算法、堆内存管理方法、SLAB内存管理算法。小堆内存管理模块主要针对系统资源比较少,一般用于小于2M内存空间的系统;堆内存可以应用于多块不连续的内存堆,SLAB内存管理模块则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法。三种内存管理模块在系统运行时只能选择其中之一或者完全不使用动态堆内存管理器。

        三种管理模块提供的API接口完全相同,小堆内存管理算法接口在mem.c,堆内存管理方法在memheap.c文件中定义,SLAB内存管理模块在slab.c文件中定义。

内存管理方法 适用场景 宏定义设置 接口定义位置
小堆内存 小于2M内存空间

RT_USING_HEAP

RT_USING_SMALL_MEM

mem.c
堆内存 多块不连续的内存堆

RT_USING_MEMHEAP_AS_HEAP

RT_USING_MEMTRACE

memheap.c
SLAB 系统资源比较丰富

RT_USING_HEAP

RT_USING_SLAB

slab.c

        本章主要讲解静态小堆内存管理算法,其特点是内存利用率高,适用于小存储空间。

本章基于RT_Thread Nano V3.1.5版本分析

1、内存堆控制

  1.1 内存堆控制器   

        内存堆控制器由一些全局变量定义,如下所示:

static rt_uint8_t *heap_ptr;         // 内存堆首地址
static struct heap_mem *heap_end;    // 内存堆尾部节点
static struct heap_mem *lfree;       // 指向最低地址空闲块节点,用于管理空闲内存块
static struct rt_semaphore heap_sem; // 内存信号,用于临界资源权限保护
static rt_size_t mem_size_aligned;   // 对齐后小堆内存总大小
static rt_size_t used_mem;           // 记录已使用字节数
static rt_size_t max_mem;            // 记录已使用字节数的最大值

1.2 内存块节点

         内存堆链表节点如下所示,宏定义ARCH_CPU_64BIT表示系统内核为64位。

struct heap_mem
{
    rt_uint16_t magic;     /*内存块标志字,默认0x1ea0*/
    rt_uint16_t used;      /*=0表示内存块空闲,=1表示内存块被申请*/
    #ifdef ARCH_CPU_64BIT
    rt_uint32_t resv;
    #endif
    rt_size_t next, prev;  /*next表示上个内存块节点的相对位置,prev表示下个内存块节点的相对位置*/
	/*内存监视使能*/
    #ifdef RT_USING_MEMTRACE
    #ifdef ARCH_CPU_64BIT
    rt_uint8_t thread[8];   /* 记录线程名称*/
    #else
    rt_uint8_t thread[4];   /* 记录线程名称*/
    #endif
    #endif
};

1.3 内存堆管理

        小堆内存中通过一个双向链表管理内存块,每个内存块首定义一个节点,节点按照地址从小到大顺序双向连接。

        内存节点参数next, prev非指针变量,而是表示节点地址相对于堆首地址heap_ptr的偏移,通过偏移定位和连接上下内存块节点位置,例如一内存节点指针struct heap_mem *mem,其下个相邻节点位置为heap_ptr[mem->next],上个相邻节点位置为heap_ptr[mem->prev],同时,可计算出其内存块大小为

size=(&heap_ptr(mem->next)-(char*)mem-sizeof(struct heap_mem));

        空闲内存块指针*lfree指向地址最低的空闲内存块,内存申请时,从lfree指向位置开始向高地址遍历所有内存块,直至找到合适的空闲内存块。当内存块释放后,需要重新判断和定位lfree位置。

        系统内核为64位时,最小内存堆默认24字节,否则默认12字节。最小长度可调。

#ifdef ARCH_CPU_64BIT
#define MIN_SIZE 24
#else
#define MIN_SIZE 12
#endif

2、内存堆初始化

        小内存堆通过全局变量管理,将内存区对齐后,首尾各定义一个内存块节点,堆首内存节点为空闲内存块节点,堆尾节点属性是已使用,将2个节点双向连接,并将空闲内存块指针指向堆首节点。

2.1 初始化接口

/**
 * 系统堆初始化.
 * @param begin_addr 系统堆起始地址
 * @param end_addr 系统堆结束地址
 */
void rt_system_heap_init(void *begin_addr, void *end_addr)

2.2 初始化示例

        代码示例:

unsigned char heap[1024*1024];

rt_system_heap_init(heap,heap+sizeof(heap));

        内存结构图示:初始化完成后lfree指向首节点,heap_end指向尾部节点,收尾节单向链接。已使用字节数used_mem为0,已使用字节数的最大值max_mem为0。

2.3 源码分析

/**
 * 系统堆初始化.
 * @param begin_addr 系统堆起始地址
 * @param end_addr 系统堆结束地址
 */
void rt_system_heap_init(void *begin_addr, void *end_addr)
{
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿来不是梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值