zoukankan      html  css  js  c++  java
  • [RTThread 源码分析] 1. 内存管理1

    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;
    }
        


       

  • 相关阅读:
    游戏服务器的架构演进(完整版)阅读新得
    蚂蚁金服 11.11:支付宝和蚂蚁花呗的技术架构及实践阅读新得
    河北科技创新平台年报系统涉众分析
    问题账户需求分析
    2018年春季个人阅读计划
    2月26日毕设进度
    2月25日毕设进度
    2月24日毕设进度
    2月23日毕设进度
    2月22日毕设进度
  • 原文地址:https://www.cnblogs.com/lyyyuna/p/4123910.html
Copyright © 2011-2022 走看看