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;