日一二三四五六
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
allocator看的是sgi的版本,應用了兩級記憶體分配,其中預設情況下以記憶體池(memory
pool)策略解決記憶體碎片(fragment)問題,不過記憶體池(memory pool)在我看來只是眾多軟體者的乙個終極夢想.
下面就對allocator的理解說下它的問題.讀sgi stl**是通過侯捷先生的1.template class
__malloc_alloc_template:底層應用c的malloc實現,同時定義了應對記憶體告罄的處理辦法,使用了乙個控制代碼
(handler),及時模仿標準new裡面的set_new_handler讓客戶端(client)自己來處理記憶體不足的問題.
2.template class ******_alloc:這是乙個外部介面,只是進行了簡單的封裝
3.template class debug_alloc:這也是乙個外部介面,只是進行了簡單的封裝
4.template class
__default__alloc_template:從名字上也知道這就是預設的allocator.通過定義__use_malloc來設定其為預設.這個類也是應用了momory
pool策略的.
memory
pool在解決記憶體碎片(fragment),節約記憶體方面有突出貢獻,這個對於c++程式設計師來說有著巨大的吸引力,c++一直是秉承著高效的執行效率而著稱的,可以像c一樣直接操縱記憶體,通過偉大的malloc
crt(c runtime
liberary)函式.直接操縱記憶體,如果通過單步除錯,就可以看到malloc底層是通過彙編**來執行的.不遠扯了,說下sgi的memory
pool策略.
記憶體池(memory
pool)的最大問題是客戶端(client),所需要的記憶體大小是不一樣的,比如客戶端(client)或許需要4個位元組,或許需要17個位元組,這些都是不可預知的,如果上面的兩個物件都要放到記憶體池中,記憶體就要負責維護這兩個物件的大小(size_t),以方面在刪除的時候使用,但是記憶體池的設計初衷就是要節省空間,如何維護這個size_呢?那麼我定義兩個列表,非別維護4個位元組的物件和17個位元組的物件,這樣同乙個列表的物件就可以共享這個
size_t了,但是問題是如果客戶端(client)還需要乙個8個位元組的物件呢?再來乙個存放8個位元組的列表?如果還需要9個位元組呢?似乎這個方法是行不通的.
sgi的方法是將其整話,sgi的記憶體池有16個列表,非別維護8、16、24——128個位元組的物件,當使用者需要呼叫
allocator的時候,我將使用者所需要的size_t上調為8的整數倍.這樣我只要16個列表就可以解決使用者1~128個位元組的記憶體需求了.而且使用者的物件通常是8的倍數的,或者說概論比較大,另乙個方面每個列表事先存放好了20個本列表規定大小的記憶體塊(sgi將其作為char*儲存).
同時sgi的記憶體池遵循的策略是有需求的時候才初始化本列表,如果使用者從來沒有使用過128位元組的物件,那麼sgi的記憶體池內就不會有相應的列表,或者說相應的相應的列表為空.
上面用文字說明了下sgi的策略,下面從code的角度出發.
一 個標準stl的alloctor應該有介面有:allocate,deallocate,construce,deconstruce.sgi的
******沒有符合標準stl,沒有construct,deconstruct.sgi只有他們的全域性靜態版本.而且,sgi的
__default_alloc_template和__malloc_alloc_template不光介面不一樣,型別也與標準stl不一致,他們不需要客戶端(client)的型別引數,既是其template
class具體化的時候不需要呼叫者的型別,只需要size_t,似乎不錯,我們可以輕鬆點,不過他的******_alloc包裝的時候,有加上了這個而外的型別需求,繞來繞去總是逃不了該做的事情...哎~~~~~~
sgi的allocator首先接受使用者所需要的size_t,然後呼叫allocate(其實是客戶端這麼寫objalloc.allocate(n);),allocate向
freelist(__de****t_malloc_template的乙個資料成員,型別為乙個obj* volalite
freelist[16],既是儲存這16個列表的那個傢伙),如果freelist沒有記憶體(或者說它是空的,為初始化)那麼呼叫
refill,refill從真正的sig memory
pool中取記憶體,取出做多20個客戶端所需要的size_t大小的記憶體塊,通過chunk_alloc,取出來後將其妝扮好(就是想這20塊記憶體連線為乙個鍊錶),上交給allocate享用.真正的勞動人民是chunk_alloc,為了表彰其奉獻精神,我將其大名共只餘下:
template
char*
__default_alloc_template<__threads, __inst>::_s_chunk_alloc(size_t __size,
int& __nobjs)
預設情況下__nobjs實參為20,而且是乙個位址傳遞(引用傳遞).他做的工作可是相當相當的偉大.原始社會的時候,一切資源都相當的豐富(原始人從來不擔心石油危機),chunk_alloc從記憶體裡面取出20塊size_t大小的記憶體上交給refill,refill將其裝配後,上交
freelist,allocate從freelist中取出一塊上交給我(^_^),其實是我想allocate要記憶體,結果沒有,allocate想
refill要記憶體,refill馬上把chunk_alloc找來,於是記憶體有了.
當然記憶體要節約使用,第一次我想要乙個32位元組的記憶體,chunk_alloc找來了2*20*32個位元組的記憶體,其中的20塊上交給了refill,refill填充
freelist,freelist[3]儲存其中19個,上交給客戶端(我)乙個.下一次我要乙個8位元組的記憶體,chunk_alloc又要找記憶體了,
不過上次找來的記憶體還沒有用完(上次交了20*24,剩餘20*24,也就是剩餘480位元組),而且足夠上交refill的了(需要8*20=160),
他們我上交給他所需要的記憶體,不從系統堆(heap)裡面取用記憶體(只有chunk_alloc這樣的勞動人民知道花錢小心翼翼).這樣美好的日子一直持續著,突然有一天,chunk_alloc發現系統記憶體重要用完了,怎麼辦?怎麼向refill交差?refill一再壓迫
chunk_alloc.chunk_alloc於是去找freelist,freelist內部儲存上尚未陪客戶端(client)取走的記憶體,比如
freelist[3],中還有10塊沒有用完,也就是說有160個位元組的記憶體,那麼chunk_alloc看看內不能滿足refill的最小需求(1塊
size_t),然後毫無保留的上交上去.如果連freelist都沒有記憶體了,chunk_alloc於是向同門兄弟
__malloc_default_alloc求助(呼叫它的allocate),再那裡有記憶體不足的處理情況,或許就要std::bad_alloc
了~~~~~~世界末日!!!
姓名 [登入] [註冊]請輸入你的姓名
主頁
email (僅博主可見)郵件位址無效
請輸入驗證碼
驗證碼 * 看不清,換一張
[熱點話題]「有道難題」程式設計挑戰賽
.net 新手小組
.net頻道
china-pub 計算機圖書網上專賣店!6.5萬品種 2-8折!
china-pub 計算機絕版圖書按需印刷服務導航
首頁 新隨筆
聯絡 訂閱
管理 <2023年6月》
日一二三四五六
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
閱讀排行榜
1. stl設計思想之traits技術(188)
2. stl設計思想之記憶體管理(109)
記憶體管理之記憶體池的設計
如何更好的管理在應用程式中記憶體的使用,同時提高記憶體使用的效率,這是值得每乙個做開發的人深思的問題。記憶體池 memory pool 提供了一種比較可行的解決方案。下面就一般記憶體池的原理與設計進行 一般的記憶體池的使用,分為以下幾個過程 1.建立記憶體池。這個過程的主要任務是預先分配足夠大的記憶...
記憶體管理之記憶體定址
記憶體定址 三種記憶體位址 邏輯位址 logical address 包含機器語言指令中用來指定乙個運算元或一條指令的位址 線性位址 linear address 線性位址也稱為虛擬位址 virtual address 實體地址 physical address 用於記憶體晶元級記憶體單元定址,他們...
c 之記憶體管理
c 使用3 種不同解決方案儲存資料,區別是資料保留在記憶體中的時間 兩種儲存持續性為自動 自動變數和暫存器變數 register 沒有記憶體位址 堆疊 在函式外定義的變數和使用關鍵字static定義的變數的儲存持續性都為靜態.分為 3 外部鏈結性,內部鏈結性和無鏈結性 所有靜態變數都有下面的兩個初始...