[RT-Thread 源码分析] 1. 内存管理1

来源:互联网 发布:淘宝上可爱文具店 编辑:程序博客网 时间:2024/06/05 04:05
rt-thread的小内存管理是其默认的堆内存管理算法。是采用静态链表来实现的,源文件为mem.c。1.数据结构=====    struct heap_mem      {          /* magic and used flag */          rt_uint16_t magic;        // 如果此内存块被分配了,则置0x1ea0,以此标志        // 此块内存是正常分配出来的,而不是非法指针          rt_uint16_t used;      // 0:未分配;1:已分配                rt_size_t next, prev;  // 前一内存块,后一内存块      };      2.初始化动态内存堆=====    /**      * @ingroup SystemInit      *      * This function will init system heap      *      * @param begin_addr the beginning address of system page      * @param end_addr the end address of system page      */      void rt_system_heap_init(void *begin_addr, void *end_addr)      {          struct heap_mem *mem;          rt_uint32_t begin_align = RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE);            // 得到对齐后的堆内存起始地址          // 在rtdef.h中        // #define RT_ALIGN(size, align)           (((size) + (align) - 1) & ~((align) - 1))        // 使得begin_align保持四字对齐,这样对于处理器寻址时比较高效        rt_uint32_t end_align = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_ALIGN_SIZE);         // 得到对齐后的堆内存末尾地址          // #define RT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))        // 使得末尾地址向后四字对齐        RT_DEBUG_NOT_IN_INTERRUPT;                  // 确保此函数不是运行在中断例程内          // 在rtdebug.h中        // #define RT_DEBUG_NOT_IN_INTERRUPT                                             \        //    do                                                                            \        //    {                                                                             \        //        rt_base_t level;                                                          \        //        level = rt_hw_interrupt_disable();                                        \        //        if (rt_interrupt_get_nest() != 0)                                         \        //        {                                                                         \        //            rt_kprintf("Function[%s] shall not used in ISR\n", __FUNCTION__);     \        //            RT_ASSERT(0)                                                          \        //        }                                                                         \        //        rt_hw_interrupt_enable(level);                                            \        //    }                                                                             \        //    while (0)        // 可以判断出是否处于中断嵌套中,保证初始化内存堆不在中断中执行        /* alignment addr */          if ((end_align > (2 * SIZEOF_STRUCT_MEM)) &&                             ((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align))          // 确保可用动态堆内存大小至少大于可等于2个内存块控制结构大小        // 在初始化中,分配两个内存控制块,一个指向开始,一个指向末尾        {              /* calculate the aligned memory size */              mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM;               // 计算出还可以分配的内存大小,要减去两个内存控制块所占的空间        }          else          {              rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n",                         (rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);                    return;          }                /* point to begin address of heap */          heap_ptr = (rt_uint8_t *)begin_align;             // heap_ptr为静态全局变量,指用堆内存起始地址                RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n",                                      (rt_uint32_t)heap_ptr, mem_size_aligned));                /* initialize the start of the heap */          mem        = (struct heap_mem *)heap_ptr;            // 将堆的起始地址初始化为一个内存块         mem->magic = HEAP_MAGIC;        // 初始化为0x1ea0,用来标示          mem->next  = mem_size_aligned + SIZEOF_STRUCT_MEM;            // 链表的下一个为末尾地址,需要加一个内存块指块的大小,即        // 可用大小为整个空间。且这里是用的相对位置        mem->prev  = 0;                 // 无前一个内存块          mem->used  = 0;                 // 初始化为未使用                /* initialize the end of the heap */          heap_end        = (struct heap_mem *)&heap_ptr[mem->next];           // 指向末尾内存块,将末尾地址初始化为一个内存块        heap_end->magic = HEAP_MAGIC;          heap_end->used  = 1;            // 末尾内存块初始化为已使用          heap_end->next  = mem_size_aligned + SIZEOF_STRUCT_MEM;           // 下一个内存块指向自己          heap_end->prev  = mem_size_aligned + SIZEOF_STRUCT_MEM;           // 前一个内存块也指向自己                rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);    // 初始化堆内存信号量为1                /* initialize the lowest-free pointer to the start of the heap */          lfree = (struct heap_mem *)heap_ptr;             // lfree始终指向最小位置的空闲内存块,这里指向初始地址    }    3.分配内存=====/** * Allocate a block of memory with a minimum of 'size' bytes. * * @param size is the minimum size of the requested block in bytes. * * @return pointer to allocated memory or NULL if no free memory was found. */void *rt_malloc(rt_size_t size){    rt_size_t ptr, ptr2;    struct heap_mem *mem, *mem2;    RT_DEBUG_NOT_IN_INTERRUPT;    if (size == 0)        return RT_NULL;    if (size != RT_ALIGN(size, RT_ALIGN_SIZE))        RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n",                                    size, RT_ALIGN(size, RT_ALIGN_SIZE)));    else        RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size));    /* alignment size */    size = RT_ALIGN(size, RT_ALIGN_SIZE);    // 首先将地址对齐    if (size > mem_size_aligned)    // 如果地址大于可用地址,则说明内存不够用了    {        RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n"));        return RT_NULL;    }    /* every data block must be at least MIN_SIZE_ALIGNED long */    if (size < MIN_SIZE_ALIGNED)        size = MIN_SIZE_ALIGNED;    // 在mem.c中    // #define MIN_SIZE 12    // #define MIN_SIZE_ALIGNED     RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE)    // 分配的内存必须要大于最小要求        /* take memory semaphore */    rt_sem_take(&heap_sem, RT_WAITING_FOREVER);    // 获取信号量,和其他内存分配函数保持同步    for (ptr = (rt_uint8_t *)lfree - heap_ptr;         ptr < mem_size_aligned - size;         ptr = ((struct heap_mem *)&heap_ptr[ptr])->next)        // 从最小位置内存块开始寻找空闲的内存块。ptr指的是相对位置    {        mem = (struct heap_mem *)&heap_ptr[ptr];        // 指向遍历得到的内存块,然后进行判断是否可用和大小是否满足        if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size)        {            /* mem is not used and at least perfect fit is possible:             * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */            // 第一句判断是否是未使用的内存块            // 然后判断除去内存控制块之后的内存空间大小是否满足要求                        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >=                (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED))            {                /* (in addition to the above, we test if another struct heap_mem (SIZEOF_STRUCT_MEM) containing                 * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')                 * -> split large block, create empty remainder,                 * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if                 * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,                 * struct heap_mem would fit in but no data between mem2 and mem2->next                 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty                 *       region that couldn't hold data, but when mem->next gets freed,                 *       the 2 regions would be combined, resulting in more free memory                 */                // 这里,当这个内存块够分配所需大小,且剩下的空间还能分配一个满足最小空间的内存块                                  ptr2 = ptr + SIZEOF_STRUCT_MEM + size;                // 这段内存被分成两个块,ptr2指向后一个空闲块                /* create mem2 struct */                // mem2指向了后一个内存块                mem2       = (struct heap_mem *)&heap_ptr[ptr2];                mem2->used = 0;                mem2->next = mem->next;                mem2->prev = ptr;                // 这里实现的是一个链表的插入。m                /* and insert it between mem and mem->next */                // 插入完成之后,mem为新分配的那个内存块                // mem2为新的空闲内存块                mem->next = ptr2;                mem->used = 1;                if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM)                // 如果后一个内存块mem2不是末尾,则让其mem2的prev指向这个空闲内存块                {                    ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;                }#ifdef RT_MEM_STATS                used_mem += (size + SIZEOF_STRUCT_MEM);                if (max_mem < used_mem)                    max_mem = used_mem;#endif            }            else            {   // 空闲的只够本次分配                /* (a mem2 struct does no fit into the user data space of mem and mem->next will always                 * be used at this point: if not we have 2 unused structs in a row, plug_holes should have                 * take care of this).                 * -> near fit or excact fit: do not split, no mem2 creation                 * also can't move mem->next directly behind mem, since mem->next                 * will always be used at this point!                 */                mem->used = 1;#ifdef RT_MEM_STATS                used_mem += mem->next - ((rt_uint8_t*)mem - heap_ptr);                if (max_mem < used_mem)                    max_mem = used_mem;#endif            }            /* set memory block magic */            mem->magic = HEAP_MAGIC;            if (mem == lfree)            // 如果更好是一个最小位置空闲内存块            {                /* Find next free block after mem and update lowest free pointer */                // 寻找下一个空闲内存块,并更新lfree的值,使其指向最小位置内存块                while (lfree->used && lfree != heap_end)                    lfree = (struct heap_mem *)&heap_ptr[lfree->next];                RT_ASSERT(((lfree == heap_end) || (!lfree->used)));            }            rt_sem_release(&heap_sem);            RT_ASSERT((rt_uint32_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_uint32_t)heap_end);            RT_ASSERT((rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);            RT_ASSERT((((rt_uint32_t)mem) & (RT_ALIGN_SIZE-1)) == 0);            RT_DEBUG_LOG(RT_DEBUG_MEM,                         ("allocate memory at 0x%x, size: %d\n",                           (rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),                          (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));            RT_OBJECT_HOOK_CALL(rt_malloc_hook,                                (((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size));            /* return the memory data except mem struct */            return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM;            // 返回内存块地址,不包括内存控制块        }    }    rt_sem_release(&heap_sem);    // 都不符合,返回RT_NULL    return RT_NULL;}