1 <strong>Constructors</strong> 2 // Constructors used to create allocator objects. 3 allocator(); // Default constructor 4 allocator(const allocator<Type>& _Right); // Copy constructor 5 template<class Other> // Template copy constructor 6 allocator(const allocator<Other>& _Right); 7 8 <strong>Typedefs</strong> 9 const_pointer // A type that provides a constant pointer to the type of object managed by the allocator. 10 const_reference // A type that provides a constant reference to type of object managed by the allocator. 11 difference_type // A signed integral type that can represent the difference between values of pointers to the type of object managed by the allocator. 12 pointer // A type that provides a pointer to the type of object managed by the allocator. 13 reference // A type that provides a reference to the type of object managed by the allocator. 14 size_type // An unsigned integral type that can represent the length of any sequence that an object of template class allocator can allocate. 15 value_type // A type that is managed by the allocator. 16 17 <strong>Member Functions</strong> 18 // Finds the address of an object whose value is specified. 19 pointer (reference _Val) const; 20 const_pointer (const_reference _Val) const; 21 22 // Allocates a block of memory large enough to store at least some specified number of elements. 23 pointer allocate(size_type _Count, const void* _Hint); 24 25 // Constructs a specific type of object at a specified address that is initialized with a specified value. 26 void construct(pointer _Ptr, const Type& _Val); 27 28 // Frees a specified number of objects from storage beginning at a specified position. 29 void deallocate(pointer _Ptr, size_type _Count); 30 31 // Calls an objects destructor without deallocating the memory where the object was stored. 32 void destroy(pointer _Ptr); 33 34 // Returns the number of elements of type Type that could be allocated by an object of class allocator before the free memory is used up. 35 size_type max_size( ) const; 36 37 // A structure that enables an allocator for objects of one type to allocate storage for objects of another type. 38 template<class _Other> 39 struct rebind { 40 typedef allocator<_Other> other; 41 }; 42 43 <strong>Operators overload</strong> 44 template<class Other> 45 allocator<Type>& operator=(const allocator<Other>& _Right); // Assignment operator 46 47
1 template<class T, class Alloc> 2 class simple_alloc { 3 public: 4 static T *allocate(size_t n) 5 { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); } 6 static T *allocate(void) 7 { return (T*) Alloc::allocate(sizeof (T)); } 8 static void deallocate(T *p, size_t n) 9 { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); } 10 static void deallocate(T *p) 11 { Alloc::deallocate(p, sizeof (T)); } 12 };
1 <span style="font-size:10px;">// 基於malloc()的配置器.一般比第二級配置器(__default_alloc_template)慢. 2 // 一般是線程安全的,而且對存儲空間的使用更加高效. 3 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG 4 # ifdef __DECLARE_GLOBALS_HERE 5 void (* __malloc_alloc_oom_handler)() = 0; // 內存不足處理函數指針 6 // g++ 2.7.2 does not handle static template data members. 7 # else 8 extern void (* __malloc_alloc_oom_handler)(); 9 # endif 10 #endif 11 12 template <int inst> // 沒有模版型別參數,至於非型別參數inst沒有用到 13 class __malloc_alloc_template { 14 private: // 用來處理內存不足的狀況 15 static void *oom_malloc(size_t); 16 static void *oom_realloc(void *, size_t); 17 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG 18 static void (* __malloc_alloc_oom_handler)(); 19 #endif 20 21 public: 22 23 static void * allocate(size_t n) 24 { 25 void *result = malloc(n); // 直接調用malloc() 26 if (0 == result) 27 result = oom_malloc(n); // 內存申請失敗,調用內存不足處理函數 28 return result; 29 } 30 31 static void deallocate(void *p, size_t /* n */) 32 { 33 free(p); // 直接調用free() 34 } 35 36 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz) 37 { 38 void * result = realloc(p, new_sz); // 直接使用realloc() 39 if (0 == result) 40 result = oom_realloc(p, new_sz); // 內存申請失敗,調用內存不足處理函數 41 return result; 42 } 43 44 // 指定內存不足處理函數句柄 45 static void (* set_malloc_handler(void (*f)()))() 46 { 47 void (* old)() = __malloc_alloc_oom_handler; 48 __malloc_alloc_oom_handler = f; 49 return(old); 50 } 51 52 }; 53 54 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG 55 template <int inst> 56 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0; // 初值爲0,需client設定 57 #endif 58 59 // 內存不足處理函數:malloc()申請內存失敗 60 template <int inst> 61 void * __malloc_alloc_template<inst>::oom_malloc(size_t n) 62 { 63 void (* my_malloc_handler)(); 64 void *result; 65 66 for (;;) { // 不斷嘗試 67 my_malloc_handler = __malloc_alloc_oom_handler; 68 if (0 == my_malloc_handler) { 69 __THROW_BAD_ALLOC; } // client未設定處理函數,直接拋出異常 70 (*my_malloc_handler)(); // 調用內存不足處理函數 71 result = malloc(n); // 再次嘗試申請內存 72 if (result) 73 return(result); // 申請成功 74 } 75 } 76 77 // 內存不足處理函數:realloc()申請內存失敗(與oom_malloc()相似) 78 template <int inst> 79 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n) 80 { 81 void (* my_malloc_handler)(); 82 void *result; 83 84 for (;;) { 85 my_malloc_handler = __malloc_alloc_oom_handler; 86 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } 87 (*my_malloc_handler)(); 88 result = realloc(p, n); 89 if (result) return(result); 90 } 91 } 92 93 typedef __malloc_alloc_template<0> malloc_alloc; // inst直接被指定爲0</span>
1 // 多線程搞不懂,故去掉了線程相關代碼,留待之後分析 2 template <bool threads, int inst> 3 class __default_alloc_template { 4 5 private: 6 // Really we should use static const int x = N 7 // instead of enum { x = N }, but few compilers accept the former. 8 // 唉,爲了兼容性,考慮得太周到了 9 # ifndef __SUNPRO_CC 10 enum {__ALIGN = 8}; 11 enum {__MAX_BYTES = 128}; 12 enum {__NFREELISTS = __MAX_BYTES/__ALIGN}; 13 # endif 14 // 內存對齊:將bytes上調至8的倍數 15 static size_t ROUND_UP(size_t bytes) { 16 return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1)); 17 } 18 __PRIVATE: 19 // free_list的節點構造 20 union obj { 21 union obj * free_list_link; 22 char client_data[1]; /* The client sees this. 這裏沒搞懂 */ 23 }; 24 private: 25 # ifdef __SUNPRO_CC 26 static obj * __VOLATILE free_list[]; 27 // Specifying a size results in duplicate def for 4.1 28 # else 29 static obj * __VOLATILE free_list[__NFREELISTS]; // free_list數組,16個元素 30 # endif 31 // 根據bytes大小獲取free_list的數組下標,從0開始 32 static size_t FREELIST_INDEX(size_t bytes) { 33 return (((bytes) + __ALIGN-1)/__ALIGN - 1); 34 } 35 36 // Returns an object of size n, and optionally adds to size n free list. 37 // 返回一個大小爲n的對象,並可能加入大小爲n的其它區塊到free list中 38 static void *refill(size_t n); 39 40 // Allocates a chunk for nobjs of size "size". nobjs may be reduced 41 // if it is inconvenient to allocate the requested number. 42 // 配置一塊空間,可容納nobjs個大小爲"size"的區塊 43 // 若是不能配置nobjs個區塊,nobjs的大小可能會減小(按引用傳遞的) 44 static char *chunk_alloc(size_t size, int &nobjs); 45 46 // 內存池狀態 47 static char *start_free; // 內存池起始位置。只在chunk_alloc()中變化 48 static char *end_free; // 內存池結束位置。只在chunk_alloc()中變化 49 static size_t heap_size; // 從堆中申請的內存大小 50 51 public: 52 53 /* n must be > 0 */ 54 static void * allocate(size_t n) 55 { 56 obj * __VOLATILE * my_free_list; 57 obj * __RESTRICT result; 58 59 if (n > (size_t) __MAX_BYTES) { 60 return(malloc_alloc::allocate(n)); // n大於128byte,直接調用第一級配置器 61 } 62 my_free_list = free_list + FREELIST_INDEX(n); // 從16個free_list中獲取合適的一個 63 result = *my_free_list; 64 if (result == 0) { 65 void *r = refill(ROUND_UP(n)); // 沒有可用的free_list,從新填充free_list 66 return r; 67 } 68 // 調整free_list:將已使用的內存區塊從free_list中移除 69 *my_free_list = result -> free_list_link; 70 return (result); 71 }; 72 73 /* p may not be 0 */ 74 static void deallocate(void *p, size_t n) 75 { 76 obj *q = (obj *)p; 77 obj * __VOLATILE * my_free_list; 78 79 if (n > (size_t) __MAX_BYTES) { 80 malloc_alloc::deallocate(p, n); // n大於128byte,直接調用第一級配置器 81 return; 82 } 83 my_free_list = free_list + FREELIST_INDEX(n); // 從16個free_list中獲取合適的一個 84 // 調整free_list: 將回收內存區塊從新添加到free_list中 85 q -> free_list_link = *my_free_list; 86 *my_free_list = q; 87 } 88 89 static void * reallocate(void *p, size_t old_sz, size_t new_sz); 90 91 } ; 92 93 // static數據的定義與初值設定 94 template <bool threads, int inst> 95 char *__default_alloc_template<threads, inst>::start_free = 0; 96 97 template <bool threads, int inst> 98 char *__default_alloc_template<threads, inst>::end_free = 0; 99 100 template <bool threads, int inst> 101 size_t __default_alloc_template<threads, inst>::heap_size = 0; 102 103 template <bool threads, int inst> 104 __default_alloc_template<threads, inst>::obj * __VOLATILE 105 __default_alloc_template<threads, inst> ::free_list[ 106 # ifdef __SUNPRO_CC 107 __NFREELISTS 108 # else 109 __default_alloc_template<threads, inst>::__NFREELISTS 110 # endif 111 ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 112 // The 16 zeros are necessary to make version 4.1 of the SunPro 113 // compiler happy. Otherwise it appears to allocate too little 114 // space for the array. 115 116 117 118 /* We allocate memory in large chunks in order to avoid fragmenting */ 119 /* the malloc heap too much. */ 120 /* We assume that size is properly aligned. */ 121 /* We hold the allocation lock. */ 122 // 爲了不堆中有過多的內存碎片,咱們每次申請一大塊內存空間 123 // 咱們假定這個空間大小是內存對齊的 124 template <bool threads, int inst> 125 char* 126 __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs) 127 { 128 char * result; 129 size_t total_bytes = size * nobjs; 130 size_t bytes_left = end_free - start_free; // 內存池剩餘空間大小 131 132 if (bytes_left >= total_bytes) { // 內存池剩餘空間徹底知足需求量 133 result = start_free; 134 start_free += total_bytes; 135 return(result); 136 } else if (bytes_left >= size) { // 內存池剩餘空間知足至少一個區塊 137 nobjs = bytes_left/size; // 調整nobjs的值 138 total_bytes = size * nobjs; 139 result = start_free; 140 start_free += total_bytes; 141 return(result); 142 } else { // 內存池剩餘空間連一個區塊都知足不了 143 // 計算需從堆中申請的內存塊大小 144 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); 145 146 // 先把內存池剩餘空間分配給合適的free_list 147 if (bytes_left > 0) { 148 obj * __VOLATILE * my_free_list = 149 free_list + FREELIST_INDEX(bytes_left); 150 151 ((obj *)start_free) -> free_list_link = *my_free_list; 152 *my_free_list = (obj *)start_free; 153 } 154 155 start_free = (char *)malloc(bytes_to_get); // 從堆中申請內存,補充內存池 156 if (0 == start_free) { // 申請內存失敗 157 int i; 158 obj * __VOLATILE * my_free_list, *p; 159 // Try to make do with what we have. That can't 160 // hurt. We do not try smaller requests, since that tends 161 // to result in disaster on multi-process machines. 162 // 先嚐試檢查咱們手上(free_list)擁有的東西。這不會形成傷害。 163 // 咱們不打算檢查比size更小的區塊,由於那在多進程機器上容易致使災難。 164 for (i = size; i <= __MAX_BYTES; i += __ALIGN) { 165 my_free_list = free_list + FREELIST_INDEX(i); 166 p = *my_free_list; 167 if (0 != p) { // 存在未用區塊 168 // 釋放該未用區塊 169 *my_free_list = p -> free_list_link; 170 start_free = (char *)p; 171 end_free = start_free + i; 172 return(chunk_alloc(size, nobjs)); // 遞歸調用本身,從新分配 173 // Any leftover piece will eventually make it to the 174 // right free list. 175 // 任何內存池剩餘空間終將被編入適當的free list 176 } 177 } 178 179 // 55,山窮水盡了 180 end_free = 0; 181 // 調用第一級配置器,看看內存不足處理函數能不能起做用 182 start_free = (char *)malloc_alloc::allocate(bytes_to_get); 183 // This should either throw an 184 // exception or remedy the situation. Thus we assume it 185 // succeeded. 186 // 要麼拋出異常,要麼內存不足的狀況得以改善,咱們假定它成功了 187 } 188 heap_size += bytes_to_get; 189 end_free = start_free + bytes_to_get; 190 return(chunk_alloc(size, nobjs)); // 遞歸調用本身,從新分配 191 } 192 } 193 194 195 /* Returns an object of size n, and optionally adds to size n free list.*/ 196 /* We assume that n is properly aligned. */ 197 /* We hold the allocation lock. */ 198 // 返回一個大小爲n的指針對象,而且有可能會爲適當的free list增長節點 199 // 假定n已經適當調整到8的倍數了 200 template <bool threads, int inst> 201 void* __default_alloc_template<threads, inst>::refill(size_t n) 202 { 203 int nobjs = 20; // 缺省取得20個新節點 204 char * chunk = chunk_alloc(n, nobjs); 205 obj * __VOLATILE * my_free_list; 206 obj * result; 207 obj * current_obj, * next_obj; 208 int i; 209 210 if (1 == nobjs) 211 return(chunk); // 只得到一個節點,直接返回 212 // 不然準備調整free list,歸入新節點 213 my_free_list = free_list + FREELIST_INDEX(n); // 找到合適的free list 214 215 /* Build free list in chunk */ 216 // 歸入新節點 217 result = (obj *)chunk; 218 *my_free_list = next_obj = (obj *)(chunk + n); 219 for (i = 1; ; i++) { 220 current_obj = next_obj; 221 next_obj = (obj *)((char *)next_obj + n); 222 if (nobjs - 1 == i) { 223 current_obj -> free_list_link = 0; 224 break; 225 } else { 226 current_obj -> free_list_link = next_obj; 227 } 228 } 229 return(result); 230 } 231 232 template <bool threads, int inst> 233 void* 234 __default_alloc_template<threads, inst>::reallocate(void *p, 235 size_t old_sz, 236 size_t new_sz) 237 { 238 void * result; 239 size_t copy_sz; 240 241 if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES) { 242 return(realloc(p, new_sz)); // 疑問:這裏怎麼不直接調用第一級配置器裏面的realloc 243 } 244 if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p); 245 result = allocate(new_sz); 246 copy_sz = new_sz > old_sz? old_sz : new_sz; 247 memcpy(result, p, copy_sz); 248 deallocate(p, old_sz); 249 return(result); 250 } 251 252 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc; 253 typedef __default_alloc_template<false, 0> single_client_alloc;