SGISTL原始碼閱讀三 空間配置器下(記憶體池memory pool)
阿新 • • 發佈:2018-11-12
SGISTL原始碼閱讀三 空間配置器下(記憶體池memory pool)
前言
在上一個部落格我們講述了空間配置器的第二級配置器,它的關鍵點free-lists是依賴於記憶體池的。在refill
中我們通過呼叫chunk_alloc
函式來申請區塊,chunk_alloc
的作用就是從記憶體池中取空間給free-lists使用。下面我們通過原始碼來解讀它。
深入原始碼
template <bool threads, int inst> char* //注意,此處nobjs傳的是引用 __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; //如果剩餘空間大於所申請的空間(nobjs個size大小) if (bytes_left >= total_bytes) { //調整記憶體池的起始地址後返回result result = start_free; start_free += total_bytes; return(result); //如果剩餘空間大於一個size } else if (bytes_left >= size) { //調整nobjs nobjs = bytes_left/size; total_bytes = size * nobjs; result = start_free; //調整記憶體池的起始地址,將記憶體池中所有的空間都返回給free-lists使用 start_free += total_bytes; return(result); //記憶體池中的空間不夠了(重點) } else { //這裡我們可以看到記憶體池向記憶體所申請的空間是total_bytes的兩倍+附加量 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); // 如果記憶體池不為空,將其置為空(把所有容量都供free-lists使用) if (bytes_left > 0) { //找到對應的free-list並新增進去 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; // Try to make do with what we have. That can't // hurt. We do not try smaller requests, since that tends // to result in disaster on multi-process machines. //從區塊大小更大的free-list中去獲取容量 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)); // Any leftover piece will eventually make it to the // right free list. } } //如果失敗了,就只能呼叫第一級配置器,從oom中尋求解決方案 //(如果oom機制也沒有解決,那麼會丟擲一個異常,詳見第一級配置器https://blog.csdn.net/lyn_00/article/details/83929578) end_free = 0; // In case of exception. start_free = (char *)malloc_alloc::allocate(bytes_to_get); // This should either throw an // exception or remedy the situation. Thus we assume it // succeeded. } //走到這裡,說明已經成功申請了total_bytes的兩倍+附加量的空間 heap_size += bytes_to_get; end_free = start_free + bytes_to_get; //最後遞迴呼叫自己,修正nobjs的值 return(chunk_alloc(size, nobjs)); } }
簡要描述一下chunk_alloc
的機制
1.如果記憶體池中的容量足夠那麼直接將total_bytes(size*nobjs)的空間供free-lists使用。
2.如果記憶體池中的容量沒那麼多,但是超過一個size大小,就改變nobjs的值,將記憶體池中所有的空間給free-lists使用。
3.如果記憶體池中的容量連一個size大小都沒有(這種情況是最複雜的)
(1)將記憶體池中的容量置零
(2)申請total_bytes的兩倍+附加量這麼大的空間,如果申請成功了,遞迴呼叫它本身,將申請到的容量一半給free-lists,一半存留在記憶體池中,如果申請失敗,見(3)
(3)在free-lists中尋找更大的free-list收回至記憶體池,再遞迴呼叫它本身。如果失敗,見(4)
(4)這種情況就是最壞的情況了,我們把它交給第一級配置器的oom機制去處理,最壞的結果是丟擲異常。
總結
之前在學習第二級配置器的時候有一個疑惑,現在就清楚了,記憶體池中處理了申請不到記憶體的情況。
現在我們對SGISTL的配置器應該也有了一個比較深入的理解。