1. 程式人生 > >stl第二級空間配置器詳解(1)

stl第二級空間配置器詳解(1)

       SGI STL考慮到小型記憶體區塊的碎片問題,設計了雙層級配置器,第一級配置直接使用malloc()和free();第二級配置器則視情況採用不同的策略,當配置區大於128bytes時,直接呼叫第一級配置器;當配置區塊小於128bytes時,遍不借助第一級配置器,而使用一個memory pool來實現。究竟是使用第一級配置器還是第二級配置器,由一個巨集定義來控制。SGI中預設使用第二級配置器。

       第一級配置器實現的比較簡單,呼叫malloc()申請記憶體,申請失敗的時候,將丟擲bad_alloc異常。下邊我著重介紹下二級配置器的實現思路。

      上邊提到了第二級配置器視情況不同而採用不同的策略;其主要目的是避免太多小額區塊造成記憶體的碎片。通常情況下,當配置區大於128bytes時,配置器視之為“足夠大”而直接呼叫一級配置器,當配置區塊小於128bytes時,就以記憶體池來管理,具體做法是:

        sgi二級配置器會將任何小額區塊的記憶體需求量上調至8的倍數,(例如需求是30bytes,則自動調整為32bytes),並且在它內部會維護16個free-list, 各自管理大小分別為8, 16, 24,…,128bytes的小額區塊,這樣當有小額記憶體配置需求時,直接從對應的free list中拔出對應大小的記憶體(8的倍數);當客戶端歸還記憶體時,將根據歸還記憶體塊的大小,將需要歸還的記憶體插入到對應free list的最頂端。如下圖:

        

                                                                                                                    圖1

      那麼什麼是free-list呢?

      首先我們看下free-list的定義

      上邊free-list節點定義得非常巧妙,與普通連結串列節點採用struct不同,這裡採用的是union;主要原因是由於為了維護free-list連結串列,每個節點需要額外的指標(指向下一個節點),這樣就會造成一種記憶體浪費。為了避免這種負擔,所以採用的union,根據union的特點,從第一個欄位看,obj可以看作一個指標,指向連結串列中的下一個節點;從第二個欄位看,obj也可以視為一個指標,不過是指向實際的記憶體區,如圖1所示,這種一物兩用的結果,就是不會為了維護連結串列所必須的指標而造成記憶體浪費。(因為stl容器是儲存物件的,所以其自身資訊當然要求是儘可能的少佔用記憶體)。

      下邊我們根據一個圖來講下第二級空間配置器分配及歸還記憶體區塊的過程:

      記憶體分配:

     

 圖2

            如上,我們要申請96bytes的記憶體(由於其內部有自動調整機制,所以有可能89~95bytes的申請也會自動上調到96bytes), 首先確定需要在第幾號free-list中獲取,如圖示是第11號free-list my_free_list,然後獲取這個第一個元素(即第一塊記憶體)的地址賦值給result,再調整my_free_list讓其指向下一個區塊。

           記憶體歸還:


圖3

跟配置記憶體類似,同樣是先尋找對應的free list,然後將要歸還的記憶體塊插入到對應free list的頭部。
不過在記憶體配置的過程中,我們還需要處理這種情況:當對應free list沒有可用區塊時,就需要給對應的free list重新填充記憶體。如下圖:
圖4 
//傳回一個大小為 n的物件,並且有時候會為適當的freelist增加節點. 
//假設 n已經適當上調至 8的倍數。
template <bool threads, int inst> 
void* __default_alloc_template<threads, inst>::refill(size_t n) 
{ 
 int nobjs = 20; 
// 呼叫 chunk_alloc(),嘗試取得 nobjs個區塊做為 free list的新節點。
 // 注意引數 nobjs是pass by reference。
 char * chunk =chunk_alloc(n, nobjs);
obj * volatile * my_free_list; 
 obj * result; 
 obj * current_obj, * next_obj; 
 int i; 
第 2 章空間配置器(allocator)
// 如果只獲得一個區塊,這個區塊就撥給呼叫者用,free list無新節點。
 if (1 == nobjs) return(chunk); 
// 否則準備調整 free list,納入新節點。
 my_free_list = free_list + FREELIST_INDEX(n); 
// 以下在 chunk空間內建立freelist
 result = (obj *)chunk; //這一塊準備傳回給客端
// 以下導引 free list指向新配置的空間(取自記憶池)
 *my_free_list = next_obj = (obj *)(chunk + n); 
// 以下將 free list 的各節點串接起來。
 for (i = 1; ; i++) {//從 1 開始,因為第 0 個將傳回給客端
 current_obj = next_obj; 
 next_obj = (obj *)((char *)next_obj + n); 
 if (nobjs - 1 == i) { 
 current_obj -> free_list_link = 0; 
 break; 
 } else { 
 current_obj -> free_list_link = next_obj; 
 } 
 } 
 return(result); 
} 

        refill()函式完成的主要功能是:根據所需要申請的區塊的大小n,呼叫chunk_alloc(n, nobjs); 預設申請nobjs個區塊(預設為20,又可能不足20,nobjs是引用傳遞);如果申請的區塊只有一個,那麼直接返回,free list仍舊無可用區塊,如果大於1,那麼將第一個chunk塊作為返回值,其餘的chunk按照n劃分為free list的節點,並將其串接到free list中區。最後free list頭節點會指向到新分配的chunk。

        綜上,我便將stl二級空間配置的空間的配置,回收,以及重新填充大小詳細介紹了一遍,下篇將繼續介紹記憶體池的設計。

相關推薦

stl第二空間配置(1)

       SGI STL考慮到小型記憶體區塊的碎片問題,設計了雙層級配置器,第一級配置直接使用malloc()和free();第二級配置器則視情況採用不同的策略,當配置區大於128bytes時,直接呼叫第一級配置器;當配置區塊小於128bytes時,遍不借助第一級配置器,而使用一個memory pool來

STL深入學習】SGI STL空間配置(二)-第二空間配置

本文講解SGI STL空間配置器的第二級配置器。 相比第一級配置器,第二級配置器多了一些機制,避免小額區塊造成記憶體的碎片。不僅僅是碎片的問題,配置時的額外負擔也是一個大問題。因為區塊越小,額外負擔所佔的比例就越大。 額外負擔是指動態分配記憶體塊的時候,位於其頭部的額外資訊

SGI STL空間配置-第一空間配置

一、SGI STL配置器簡介 如果要了解STL的實現,必須要了解空間配置器,因為整個STL的操作物件都放在容器之內,而容器一定需要配置空間以存放資料等資料。allocator叫做空間配置器而不是記憶體配置器,因為空間不一定是記憶體,也可以是磁碟或者其他

nginx 實戰--第二章 nginx配置檔案

1.nginx 配置檔案結構 配置檔案結構 全域性配置(user、worker_processes、error_log、pid) events(網路連線相關,worker_connections) http(最重要的部分,大部分功能都放這裡) server(虛擬主機相

C++ STL學習之 空間配置(allocator)

標籤(空格分隔): C++ STL 眾所周知,一般情況下,一個程式包括資料結構和相應的演算法,而資料結構作為儲存資料的組織形式,與記憶體空間有著密切的聯絡. 在C++ STL中,空間配置器便是用來實現記憶體空間(一般是記憶體,也可以是硬碟等空間)分配的工具,他與容器聯絡緊密,每一種容器的空間分配都是通過空

STL學習筆記——空間配置

一、STL基本概念1.基本元件   容器(Container)、演算法(Algorithm)、迭代器(Iterator)、仿函式(Functor)、容器介面卡(Adapter)、空間配置器(Allocator) 2.元件關係   容器通過空間配置器獲取資料儲存空間;演算法通

STL】SGI空間配置 Allocator

//size此時已適當上調至8的倍數 template <bool threads, int inst> char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs) {

STL——模擬實現空間配置

問題 我們在日常編寫C++程式時,常常會用到我們的STL標準庫來幫助我們解決問題,這當中我們用得最多估計就是它裡面的vector、list容器了,它們帶來的便利不用多說(畢竟OJ、刷題什麼的,基本全是它們的身影),而在日常學習中我們對STL中另一大元件—空間配置器 瞭解可能

STL原始碼——SGI 空間配置

本文主要參考STL原始碼剖析,但書中對某些地方寫的不是很詳細,所以根據個人的理解增加了一些細節的說明,便於回顧。 由於小型區塊分配時可能造成記憶體破碎問題,SGI設計了兩級配置器,第一級配置器直接使用malloc和free,第二級配置器則視情況採取不同的策略:當配置的區塊超

SpringBoot第二篇:配置檔案

前言   SpringBoot 完全摒棄了xml配置的模式,幾乎做到了“零配置”。說是“幾乎”,是因為一般情況下預設的配置足夠滿足日常開發所需,但是在特殊的情況下,我們往往需要用到自定義屬性配置、自定義檔案配置、多環境配置、外部命令引導等一系列功能。   SpringBoot 使用的全域性配置檔案 appli

springmvc+Freemarker配置說明1

Freemarker使用模板技術進行檢視的渲染。自從看了Struts標籤、Freemarker、JSTL的效能對比後,我毅然決定放棄Struts標籤了!效率太差……  Spring本身支援了對Freemarker的整合。只需要配置一個針對Freemarker的檢視解析器即可。 二、Sp

STL空間配置allocator

stl六大元件簡介 我們知道,stl有容器,空間配置器,介面卡,迭代器,仿函式以及演算法這6個元件,它們六者關係大概如下:容器通過配置器取得資料儲存空間,演算法通過迭代器獲取容器內容,仿函式可以協助演算法完成不同的策略變化,配接器可以修飾或套界仿函式。 侯捷在《STL原始

SGISTL原始碼閱讀二 空間配置中(第二配置__default_alloc_template)

SGISTL原始碼閱讀二 空間配置器中(第二級配置器__default_alloc_template) 引入 SGI空間配置器的做法是,如果區塊夠大,超過了128bytes,就移交給第一級配置器處理。當區塊小於128bytes時就是第二級配置器要做的事情了。 SGI的第二級配置器維護

STL空間配置-第一配置

一、SGI STL配置器簡介 SGI STL的配置器與眾不同,它與標準規範不同。如果要在程式中明確使用SGI配置器,那麼應該這樣寫: vector<int,std::alloc>iv; 他的名字是alloc,而且不接受任何引數。標準配置器的名字是allocator,而且可以接受引數。

C++標準庫——STL空間配置

但是 chunk 內容 既然 部分 如何 標識 stl源碼 strong 聲明:源碼同《STL源碼剖析》(侯捷) STL:   C++標準的模板庫,通用性高。   常見的數據結構封裝。   提供常用的通用算法。 STL六大組件:   容器 算法 叠

Nginx 服務配置

proxy erer 模塊 了解 bin 變量 linux 系統 auto 參數 目錄 Nginx 服務器配置和詳解 Nginx 模板配置 Nginx 模塊說明 核心模塊 http 模塊 Nginx 服務器配置和詳解 Nginx 扮演 web 開發的服務端入口控制

mongodb replica set 配置高性能多服務

自定義 rep error: plain sync ntc rtb fin repl mongodb的多服務器配置,以前寫過一篇文章,是master-slave模式的,請參考:詳解mongodb 主從配置。master-slave模式,不能自動實現故障轉移和恢復。所以推薦大

Docker中redis容器的主從、持久化配置)(第二篇)(共五篇)

關於redis的介紹 redis是k-v型nosql資料庫,支援字串(string)、列表(list)、集合(set)、雜湊(hash)、有序集合(zset:形如member:score的雜湊集合,其中member為成員,score為成員得分,必須為float型資料)。 綜合使用redis的

SpringBoot非官方教程 | 第二篇:Spring Boot配置檔案

springboot採納了建立生產就緒Spring應用程式的觀點。 Spring Boot優先於配置的慣例,旨在讓您儘快啟動和執行。在一般情況下,我們不需要做太多的配置就能夠讓spring boot正常執行。在一些特殊的情況下,我們需要做修改一些配置,或者需要有自己的配置屬性。 當我們

SGISTL原始碼閱讀一 空間配置上(第一配置

SGISTL原始碼閱讀一 空間配置器上(第一級配置器) 引入 我們所熟知的C++記憶體配置操作一般為 class A {} A* pa = new A(); //1.分配記憶體 2.構造物件 delete pa; //1.物件析構 2.釋放記憶體 其中new完成了兩