STL源碼分析以內存池

前言

上一節只分析了第二級配置器是由多個鏈表來存放相同內存大小, 當沒有空間的時候就向內存池索取就好了, 卻沒有具體分析內存池是怎麼保存空間的, 是否是內存池真的有用不完的內存, 本節咱們就具體來分析一下code

內存池

static data template的初始化對象

template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::start_free = 0;  // 內存池的首地址
template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::end_free = 0;    // 內存池的結束地址
template <bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;  // 屢次調用內存池, 就會更多的是給鏈表分配內存, 這就是一個增量.

這裏代碼註釋寫的很清楚了, 我就提取出來分析一下吧遞歸

  1. 內存池的大小大於須要的空間, 直接返回起始地址(nobjs默認設置爲20, 因此每次調用都會給鏈表額外的19個內存塊)
  2. 內存池的內存不足以立刻分配那麼多內存, 可是還能知足分配一個即以上的大小, 那就所有分配出去
  3. 若是一個對象的大小都已經提供不了了, 先將零碎的內存塊給一個小內存的鏈表來保存, 而後就準備調用malloc申請40塊+額外大小的內存塊(額外內存塊就由heap_size決定), 若是申請失敗跳轉到步驟4, 成功跳轉到步驟6
  4. 充分利用更大內存的鏈表, 經過遞歸來調用他們的內存塊
  5. 若是仍是沒有內存塊, 直接調用一級配置器來申請內存, 仍是失敗就拋出異常, 成功申請就繼續執行
  6. 從新修改內存起始地址和結束地址爲當前申請的地址塊, 從新調用chunk_alloc分配內存
// 內存池
template <bool threads, int inst>
char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
    char * result;
    size_t total_bytes = size * nobjs;            // 鏈表須要申請的內存大小
    size_t bytes_left = end_free - start_free;    // 內存池裏面總共還有多少內存空間

      // 內存池的大小大於須要的空間, 直接返回起始地址
    if (bytes_left >= total_bytes) 
    {
        result = start_free;
        start_free += total_bytes;  // 內存池的首地址日後移
        return(result);
    }
    // 內存池的內存不足以立刻分配那麼多內存, 可是還能知足分配一個即以上的大小, 那就按對齊方式所有分配出去
    else if (bytes_left >= size) 
    {
        nobjs = bytes_left/size;
        total_bytes = size * nobjs;
        result = start_free;
        start_free += total_bytes;  // 內存池的首地址日後移
        return(result);
    } 
    else 
    { 
        // 若是一個對象的大小都已經提供不了了, 那就準備調用malloc申請兩倍+額外大小的內存
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        // Try to make use of the left-over piece.
        // 內存池還剩下的零頭內存分給給其餘能利用的鏈表, 也就是毫不浪費一點.
        if (bytes_left > 0) 
        {
            // 鏈表指向申請內存的地址
            obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left);
            ((obj *)start_free) -> free_list_link = *my_free_list;
            *my_free_list = (obj *)start_free;
        }
        start_free = (char *)malloc(bytes_to_get);
        // 內存不足了
        if (0 == start_free) 
        {
            int i;
            obj * __VOLATILE * my_free_list, *p;
            // 充分利用剩餘鏈表的內存, 經過遞歸來申請
            for (i = size; i <= __MAX_BYTES; i += __ALIGN) 
            {   
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if (0 != p) 
                {
                    *my_free_list = p -> free_list_link;
                    start_free = (char *)p;
                    end_free = start_free + i;
                    return(chunk_alloc(size, nobjs));
                }
            }
            // 若是一點內存都沒有了的話, 就只有調用一級配置器來申請內存了, 而且用戶沒有設置處理例程就拋出異常
            end_free = 0;   // In case of exception.
            start_free = (char *)malloc_alloc::allocate(bytes_to_get);
        }
            // 申請內存成功後從新修改內存起始地址和結束地址, 從新調用chunk_alloc分配內存
            heap_size += bytes_to_get;
            end_free = start_free + bytes_to_get;
            return(chunk_alloc(size, nobjs));
    }   
}

總結

內存池的存在就是爲了能快速的提供咱們作須要的內存而且保存多餘的空間, 讓STL分配空間再也不每次都進行malloc和free的操做, 效率又頗有保障. 有時用戶申請的塊更小, 咱們也能充分的利用起來. 惟一可能不足的是咱們每次只申請char個大小, 可是內存池得到的確是8字節的大小.內存

相關文章
相關標籤/搜索