/** * This function will change the previously allocated memory block. * * @param rmem pointer to memory allocated by rt_malloc * @param newsize the required new size * * @return the changed memory block address */void *rt_realloc(void *rmem, rt_size_t newsize){ rt_size_t size; rt_size_t ptr, ptr2; struct heap_mem *mem, *mem2; void *nmem; RT_DEBUG_NOT_IN_INTERRUPT; /* alignment size */ // 首先要將地址對齊,然後計算新分配的大小 newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); if (newsize > mem_size_aligned) { // 新分配的記憶體大小不能大於總的大小 RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n")); return RT_NULL; } /* allocate a new memory block */ // 如果傳入的指標為空白,則直接調用malloc分配一個新的記憶體塊 if (rmem == RT_NULL) return rt_malloc(newsize); // 等待訊號量,防止記憶體配置競爭 rt_sem_take(&heap_sem, RT_WAITING_FOREVER); if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) { // 如果傳入的記憶體指標小於最小值和大於最大值,則為非法 // 然後釋放訊號量,退出。 /* illegal memory */ rt_sem_release(&heap_sem); return rmem; } mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); // 因為傳入的記憶體塊的地址是不包括記憶體控制塊的,這裡需要重新加上 ptr = (rt_uint8_t *)mem - heap_ptr; // 得到相對位移量 size = mem->next - ptr - SIZEOF_STRUCT_MEM; // 得到當前這個記憶體塊的大小 if (size == newsize) { /* the size is the same as */ // 如果大小沒變,則不用再次分配,直接返回 rt_sem_release(&heap_sem); return rmem; } if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) //新大小滿足要求 { /* split memory block */#ifdef RT_MEM_STATS used_mem -= (size - newsize);#endif // 這一段就是把原來的ptr擴大 // ptr2是指向後一個未用的塊 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; // 指向新的記憶體塊 mem2 = (struct heap_mem *)&heap_ptr[ptr2]; // 轉換為記憶體控制塊 mem2->magic= HEAP_MAGIC; mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; mem->next = ptr2; // 鏈表操作,不再重複 if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) { // 如果不是這個heap的末尾,就讓mem2的後一個塊的prev指向mem2 ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2; } // 這個函數處理一些零碎的空間 plug_holes(mem2); rt_sem_release(&heap_sem); return rmem; } rt_sem_release(&heap_sem); /* expand memory */ // 如果新大小不滿足要求,則直接開闢一塊記憶體 nmem = rt_malloc(newsize); if (nmem != RT_NULL) /* check memory */ { rt_memcpy(nmem, rmem, size < newsize ? size : newsize); // 將原來記憶體塊的內容拷貝到新記憶體塊中 rt_free(rmem); } return nmem;}RTM_EXPORT(rt_realloc);/** * This function will contiguously allocate enough space for count objects * that are size bytes of memory each and returns a pointer to the allocated * memory. * * The allocated memory is filled with bytes of value zero. * * @param count number of objects to allocate * @param size size of the objects to allocate * * @return pointer to allocated memory / NULL pointer if there is an error */void *rt_calloc(rt_size_t count, rt_size_t size){ void *p; RT_DEBUG_NOT_IN_INTERRUPT; /* allocate 'count' objects of size 'size' */ // 使用malloc分配 p = rt_malloc(count * size); /* zero the memory */ // 將記憶體中元素全部置零 if (p) rt_memset(p, 0, count * size); return p;}RTM_EXPORT(rt_calloc);/** * This function will release the previously allocated memory block by * rt_malloc. The released memory block is taken back to system heap. * * @param rmem the address of memory which will be released */void rt_free(void *rmem){ struct heap_mem *mem; RT_DEBUG_NOT_IN_INTERRUPT; if (rmem == RT_NULL) return; RT_ASSERT((((rt_uint32_t)rmem) & (RT_ALIGN_SIZE-1)) == 0); RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr && (rt_uint8_t *)rmem < (rt_uint8_t *)heap_end); RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem)); if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) // 確保傳入記憶體位址合法 { RT_DEBUG_LOG(RT_DEBUG_MEM, ("illegal memory\n")); return; } /* Get the corresponding struct heap_mem ... */ // 獲得傳入記憶體塊的記憶體控制塊 // 因為記憶體控制塊在記憶體塊的前部 mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); RT_DEBUG_LOG(RT_DEBUG_MEM, ("release memory 0x%x, size: %d\n", (rt_uint32_t)rmem, (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr)))); /* protect the heap from concurrent access */ rt_sem_take(&heap_sem, RT_WAITING_FOREVER); /* ... which has to be in a used state ... */ RT_ASSERT(mem->used); RT_ASSERT(mem->magic == HEAP_MAGIC); /* ... and is now unused. */ // 置位成不用狀態 mem->used = 0; mem->magic = 0; if (mem < lfree) { /* the newly freed struct is now the lowest */ // lfree指向最低可用記憶體塊控制塊地址 // 這裡更新lfree lfree = mem; }#ifdef RT_MEM_STATS used_mem -= (mem->next - ((rt_uint8_t*)mem - heap_ptr));#endif /* finally, see if prev or next are free also */ // 處理零碎的塊 plug_holes(mem); rt_sem_release(&heap_sem);}static void plug_holes(struct heap_mem *mem){ struct heap_mem *nmem; struct heap_mem *pmem; RT_ASSERT((rt_uint8_t *)mem >= heap_ptr); RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)heap_end); RT_ASSERT(mem->used == 0); /* plug hole forward */ // 把後面一個記憶體空洞填滿 // 擷取後一個記憶體控制塊 nmem = (struct heap_mem *)&heap_ptr[mem->next]; if (mem != nmem && nmem->used == 0 && (rt_uint8_t *)nmem != (rt_uint8_t *)heap_end) { /* if mem->next is unused and not end of heap_ptr, * combine mem and mem->next */ // 如果存在後一個記憶體塊,且沒有使用,且不是末尾 if (lfree == nmem) // 如果後一個是lfree { lfree = mem; // 更新lfree為mem } mem->next = nmem->next; // 鏈表操作,即刪除nmem ((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr; // 為什麼這麼煩? // 因為1. next, prev都是使用相對位址 // 2. heap_ptr和mem的指標類型不一樣 } /* plug hole backward */ // 把前一個空洞填滿 // 擷取前一個記憶體控制塊 pmem = (struct heap_mem *)&heap_ptr[mem->prev]; if (pmem != mem && pmem->used == 0) { /* if mem->prev is unused, combine mem and mem->prev */ if (lfree == mem) { lfree = pmem; // 更新lfree } pmem->next = mem->next; ((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr; // 鏈表操作,刪除 }}