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

来源:互联网 发布:网络剧合作平台 编辑:程序博客网 时间:2024/06/08 00:41
/** * 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;        // 链表操作,删除    }}