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

來源:互聯網
上載者:User
/** * 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;        // 鏈表操作,刪除    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.