[RT-Thread 源碼分析] 1. 記憶體管理1

來源:互聯網
上載者:User
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;}    

   

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.