STL原始碼剖析 空間配置器(allocator)

2021-09-19 13:28:22 字數 4253 閱讀 1040

一般容器都需要一定空間存放資料,allocator就是用來配置空間的,sgi的allocator配置的物件時記憶體。

乙個allocator通常包含兩個部分,一是記憶體配置和記憶體釋放(allocate的deallocate),二是物件構造和析構(construct和destory)。

#ifndef _jjalloc_

#define _jjalloc_

#include

//for placement new

#include

//for ptrdiff_t,size_t

#include

//for uint_max

#include

//for cerr

namespace jj

return tmp;

}template

<

class

t>

inline

void

_deallocate

(t* buffer)

template

<

classt1,

class

t2>

inline

void

_construct

(t1*p,

const t2& value)

template

<

class

t>

inline

void

_destroy

(t* ptr)

template

<

class

t>

class

allocator;

pointer allocate

(size_type n,

const

void

* hint=0)

void

deallocate

(pointer p,size_type n)

void

construct

(pointer p,

const t& value)

void

destroy

(pointer p)

pointer address

(reference x)

const_pointer const_address

(const_reference x)

size_type max_size()

const;}

;}//end of namespace jj

#endif _jjalloc_

重點是jj空間中四個模板函式:

__allocate函式模板採用了operator new來配置記憶體,即分配一塊未構造的、原始的記憶體空間。

__deallocate利用operator delete釋放上面分配的記憶體。

__construct採用定位new在給定的記憶體位址上構造物件。

__destory執行物件的析構動作。

四個部分構成了空間配置器的基礎。

sgi提供了兩個空間配置器,其中標準的allocator與上面提供的簡單空間配置器類似,效率並不高,也不推薦使用。

下面介紹sgi特殊空間配置器

sgi特殊的空間配置器稱為alloc,alloc也是由之前講述的兩部分構成:一是記憶體配置和記憶體釋放(allocate的deallocate),二是物件構造和析構(construct和destory)。

3.1.1構造和析構

以下原始碼在 。

構造工具和之前介紹的簡單空間配置器並無區別,主要區別在析構操作上,提供了兩個個版本的析構工具,乙個是銷毀單個物件,另外乙個是銷毀多個:

template

<

class

_tp>

inline

void

_destroy

(_tp* __pointer)

template

<

class

_forwarditerator

>

inline

void

_destroy

(_forwarditerator __first, _forwarditerator __last)

第二個版本通過__value_type判斷是否有物件是否有trivial destructor(無關痛癢的析構函式),然後呼叫不同的__destroy_aux,如果有執行它的析構函式(_destroy(&*__first)),如果沒有就什麼也不做,因此提高了效率:

template

<

class

_forwarditerator

>

void

__destroy_aux

(_forwarditerator __first, _forwarditerator __last, __false_type)

template

<

class

_forwarditerator

>

inline

void

__destroy_aux

(_forwarditerator, _forwarditerator, __true_type)

3.1.2空間的配置和釋放

以下原始碼在

sgi在空間配置上考慮了以下問題:

c++的記憶體配置基本操作是:operator new和operator delete,其相當於c語言的malloc和free函式。

考慮記憶體碎片的問題,sgi配置器採用雙層級配置器:

不論採用第一級還是第二級,sgi都為他們包裝了乙個介面以供使用(******_alloc)。

第一級配置器

第一級配置器採用malloc、free、realloc等執行實際記憶體操作,而不是使用operator new,因此不能直接運用c++ new-handler機制(即如果operator new無法完成操作,在丟擲bad_alloc之前會先呼叫客戶指定的處理程式,此程式稱為new-handler)。需要自己實現new-handler機制:

static

void(*

set_malloc_handler

(void

(*f)()

))()

template

<

int inst>

void

* __malloc_alloc_template

::oom_malloc

(size_t n)

(*my_malloc_handler)()

;//呼叫new-handler

result =

malloc

(n);

if(result)

return

(result);}

}

如果malloc不成功,會改用oom_malloc不斷申請,如果客戶端未設定new-handler,則丟擲異常。

第二級配置器

第二級配置器維護16個free-lists,分別管理8、16、24、32…120、128大小的區塊,客戶端配置記憶體時過程如下:

先從free-list中申請滿足大小要求並且最小的區塊,申請成功就返回給客戶端並且該free-list的指標指向下乙個區塊。

如果在該free-list中沒有申請到,就呼叫refill從記憶體池中申請20區塊大小填充該free-list。

記憶體池的操作如下:

3. 如果記憶體池水量充足,就調出20個區塊返回。

4. 如果水量不足,但還夠乙個以上區塊,就調出這些區塊然後返回。

5. 如果水量連乙個區塊都不足以提供,就從系統heap申請記憶體。在申請前,先把記憶體池中的零頭分配給free-list,比如記憶體池中還剩35位元組,就分配給區塊大小為32的free-list。

6. 從系統申請40+n的記憶體,然後將第乙個區塊交給客戶端,將剩餘19個區塊交給free-list維護,剩下的20+n個留給記憶體池。

7. 如果整個系統heap都不夠了,就查詢是否還有足夠大且沒有使用的free-list,然後釋放這些區塊(大的放入記憶體池,小的零頭被編入free-list,通過遞迴呼叫自己實現)。

參考:stl原始碼剖析

STL原始碼剖析 空間配置器

看過stl空間配置器的原始碼,總結一下 1 stl空間配置器 主要分三個檔案實現,stl construct.h 這裡定義了全域性函式construct 和destroy 負責物件的構造和析構。stl alloc.h檔案中定義了 一 二兩級配置器,彼此合作,配置器名為alloc.stl uninit...

STL原始碼剖析 空間配置器

allocator是空間配置器而不是記憶體配置器,空間不一定是記憶體,也可以是磁碟或其他輔助儲存介質。但sgi stl提供的配置器配置的物件是記憶體。sgi標準的空間配置器,std alloctor sgi定義了乙個符合部分標準,名為alloctor的配置器,效率不高,只把c 的 operator ...

STL原始碼剖析 空間配置器

由於物件的建立分為分配記憶體和呼叫建構函式兩部分,stl allocator使用alloc allocate 來分配記憶體,construct 構造物件。construct 函式只有乙個泛化的版本,destroy 函式有乙個泛化的針對迭代器的版本,destroy aux 根據是否需要呼叫析構函式進行...