RT-Thread上内存分配分析之一

1.简介

  内存分配在RTOS上还是较为常见的,除了一些特殊场合使用的RTOS(不允许malloc,free操作,防止内存碎片), 实际产品中,使用分配内存机制还是较常用。
  RTOS上的内存管理方式,分为常见的动态内存堆管理,和静态内存池管理,其中动态内存管理又分为常见的,小内存分配算法,多内存分配算法(memheap),
slab分配算法等等。RT-Thread上分配算法可以在conf中配置。

RT_USING_SMALL_MEM_AS_HEAP        小内存分配算法
RT_USING_MEMHEAP_AS_HEAP          内存堆分配
RT_USING_SLAB_AS_HEAP             SLAB分配算法

2.RTT上统一的内存接口

  上述已经提及常见的几种内存分配算法,针对内存堆管理,RTT对应用层提供了统一的调用API.(备注RTT最新的分配算法和早期有差异)

2.1 初始化堆内存

/**
 * @brief This function will init system heap.
 *
 * @param begin_addr the beginning address of system page.
 *
 * @param end_addr the end address of system page.
 */
RT_WEAK void rt_system_heap_init(void *begin_addr, void *end_addr)
{
    //针对设定的起始,结束地址,做一个4字节对齐
    rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE);
    rt_ubase_t end_align   = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE);
    RT_ASSERT(end_align > begin_align);
    /* Initialize system memory heap */
    //这里会根据用户设置内存分配算法,初始化内存分配算法
    _MEM_INIT("heap", begin_addr, end_align - begin_align);
    /* Initialize multi thread contention lock */
    //初始化内存分配互斥锁(大多数场景都有mutex,如果没有,也需要采取进临界措施)
    _heap_lock_init();
}

对于mcu起始heap地址,在bsp层都会定义清楚。参考:

#if defined(__ARMCC_VERSION)
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN      ((void *)&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#pragma section="CSTACK"
#define HEAP_BEGIN      (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN      ((void *)&__bss_end)
#endif

2.2 分配内存接口

RT_WEAK void *rt_malloc(rt_size_t size)
{
    rt_base_t level;
    void *ptr;

    /* Enter critical zone */
    //使用互斥锁,在没有的情况进临界区,关闭中断
    level = _heap_lock();
    /* allocate memory block from system heap */
    //调用统一的接口进行分配(根据不同的分配算法进行)
    ptr = _MEM_MALLOC(size);
    /* Exit critical zone */
    //解除互斥锁
    _heap_unlock(level);
    /* call 'rt_malloc' hook */
    RT_OBJECT_HOOK_CALL(rt_malloc_hook, (ptr, size));
    return ptr;
}

2.3 释放分配的内存

RT_WEAK void rt_free(void *rmem)
{
    rt_base_t level;

    /* call 'rt_free' hook */
    RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem));
    /* NULL check */
    if (rmem == RT_NULL) return;
    /* Enter critical zone */
    //进临界,对内存进行操作
    level = _heap_lock();
    _MEM_FREE(rmem);
    /* Exit critical zone */
    //退出临界
    _heap_unlock(level);
}

2.4 其它接口

其它一些接口进行内存的重新分配,分配并初始化为0。

//分配并清0
RT_WEAK void *rt_calloc(rt_size_t count, rt_size_t size);
//打印内存信息
RT_WEAK void rt_memory_info(rt_size_t *total,
                            rt_size_t *used,
                            rt_size_t *max_used)
//重新分配
RT_WEAK void *rt_realloc(void *rmem, rt_size_t newsize)

3.说明

  从上描述的源码可以看到,进行内存分配的时候会考虑临界区,在线程中使用时,会使用mutex进行互斥。 所以对于在中断里面不要使用内存分配和释放接口。 附带(RTT4.0+版本,操作heap使用mutex源码):

rt_inline rt_base_t _heap_lock(void)
{
#if defined(RT_USING_HEAP_ISR)
    return rt_hw_interrupt_disable();
#elif defined(RT_USING_MUTEX)
    if (rt_thread_self())
    //当前处于线程中,需要进行临界保护
        return rt_mutex_take(&_lock, RT_WAITING_FOREVER);
    else
        //在非线程中,例如中断
        return RT_EOK;
#else
    rt_enter_critical();
    return RT_EOK;
#endif
}