/** * 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; // 链表操作,删除 } }