Constructors // Constructors used to create allocator objects. allocator(); // Default constructor allocator(const allocator<Type>& _Right); // Copy constructor template<class Other> // Template copy constructor allocator(const allocator<Other>& _Right); Typedefs const_pointer // A type that provides a constant pointer to the type of object managed by the allocator. const_reference // A type that provides a constant reference to type of object managed by the allocator. difference_type // A signed integral type that can represent the difference between values of pointers to the type of object managed by the allocator. pointer // A type that provides a pointer to the type of object managed by the allocator. reference // A type that provides a reference to the type of object managed by the allocator. size_type // An unsigned integral type that can represent the length of any sequence that an object of template class allocator can allocate. value_type // A type that is managed by the allocator. Member Functions // Finds the address of an object whose value is specified. pointer (reference _Val) const; const_pointer (const_reference _Val) const; // Allocates a block of memory large enough to store at least some specified number of elements. pointer allocate(size_type _Count, const void* _Hint); // Constructs a specific type of object at a specified address that is initialized with a specified value. void construct(pointer _Ptr, const Type& _Val); // Frees a specified number of objects from storage beginning at a specified position. void deallocate(pointer _Ptr, size_type _Count); // Calls an objects destructor without deallocating the memory where the object was stored. void destroy(pointer _Ptr); // 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. size_type max_size( ) const; // A structure that enables an allocator for objects of one type to allocate storage for objects of another type. template<class _Other> struct rebind { typedef allocator<_Other> other; }; Operators overload template<class Other> allocator<Type>& operator=(const allocator<Other>& _Right); // Assignment operator
template<class T, class Alloc> class simple_alloc { public: static T *allocate(size_t n) { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); } static T *allocate(void) { return (T*) Alloc::allocate(sizeof (T)); } static void deallocate(T *p, size_t n) { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); } static void deallocate(T *p) { Alloc::deallocate(p, sizeof (T)); } };
// 基于malloc()的配置器.通常比第二级配置器(__default_alloc_template)慢.
// 通常是线程安全的,并且对存储空间的使用更加高效.
#ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
# ifdef __DECLARE_GLOBALS_HERE
void (* __malloc_alloc_oom_handler)() = 0; // 内存不足处理函数指针
// g++ 2.7.2 does not handle static template data members.
# else
extern void (* __malloc_alloc_oom_handler)();
# endif
#endif
template <int inst> // 没有模版型别参数,至于非型别参数inst没有用到
class __malloc_alloc_template {
private: // 用来处理内存不足的情况
static void *oom_malloc(size_t);
static void *oom_realloc(void *, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
static void * allocate(size_t n)
{
void *result = malloc(n); // 直接调用malloc()
if (0 == result)
result = oom_malloc(n); // 内存申请失败,调用内存不足处理函数
return result;
}
static void deallocate(void *p, size_t /* n */)
{
free(p); // 直接调用free()
}
static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
void * result = realloc(p, new_sz); // 直接使用realloc()
if (0 == result)
result = oom_realloc(p, new_sz); // 内存申请失败,调用内存不足处理函数
return result;
}
// 指定内存不足处理函数句柄
static void (* set_malloc_handler(void (*f)()))()
{
void (* old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
};
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0; // 初值为0,需client设定
#endif
// 内存不足处理函数:malloc()申请内存失败
template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;) { // 不断尝试
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler) {
__THROW_BAD_ALLOC; } // client未设定处理函数,直接抛出异常
(*my_malloc_handler)(); // 调用内存不足处理函数
result = malloc(n); // 再次尝试申请内存
if (result)
return(result); // 申请成功
}
}
// 内存不足处理函数:realloc()申请内存失败(与oom_malloc()类似)
template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;) {
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)();
result = realloc(p, n);
if (result) return(result);
}
}
typedef __malloc_alloc_template<0> malloc_alloc; // inst直接被指定为0
总结:
// 多线程搞不懂,故去掉了线程相关代码,留待以后分析 template <bool threads, int inst> class __default_alloc_template { private: // Really we should use static const int x = N // instead of enum { x = N }, but few compilers accept the former. // 唉,为了兼容性,考虑得太周到了 # ifndef __SUNPRO_CC enum {__ALIGN = 8}; enum {__MAX_BYTES = 128}; enum {__NFREELISTS = __MAX_BYTES/__ALIGN}; # endif // 内存对齐:将bytes上调至8的倍数 static size_t ROUND_UP(size_t bytes) { return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1)); } __PRIVATE: // free_list的节点构造 union obj { union obj * free_list_link; char client_data[1]; /* The client sees this. 这里没搞懂 */ }; private: # ifdef __SUNPRO_CC static obj * __VOLATILE free_list[]; // Specifying a size results in duplicate def for 4.1 # else static obj * __VOLATILE free_list[__NFREELISTS]; // free_list数组,16个元素 # endif // 根据bytes大小获取free_list的数组下标,从0开始 static size_t FREELIST_INDEX(size_t bytes) { return (((bytes) + __ALIGN-1)/__ALIGN - 1); } // Returns an object of size n, and optionally adds to size n free list. // 返回一个大小为n的对象,并可能加入大小为n的其它区块到free list中 static void *refill(size_t n); // Allocates a chunk for nobjs of size "size". nobjs may be reduced // if it is inconvenient to allocate the requested number. // 配置一块空间,可容纳nobjs个大小为"size"的区块 // 如果不能配置nobjs个区块,nobjs的大小可能会减少(按引用传递的) static char *chunk_alloc(size_t size, int &nobjs); // 内存池状态 static char *start_free; // 内存池起始位置。只在chunk_alloc()中变化 static char *end_free; // 内存池结束位置。只在chunk_alloc()中变化 static size_t heap_size; // 从堆中申请的内存大小 public: /* n must be > 0 */ static void * allocate(size_t n) { obj * __VOLATILE * my_free_list; obj * __RESTRICT result; if (n > (size_t) __MAX_BYTES) { return(malloc_alloc::allocate(n)); // n大于128byte,直接调用第一级配置器 } my_free_list = free_list + FREELIST_INDEX(n); // 从16个free_list中获取合适的一个 result = *my_free_list; if (result == 0) { void *r = refill(ROUND_UP(n)); // 没有可用的free_list,重新填充free_list return r; } // 调整free_list:将已使用的内存区块从free_list中移除 *my_free_list = result -> free_list_link; return (result); }; /* p may not be 0 */ static void deallocate(void *p, size_t n) { obj *q = (obj *)p; obj * __VOLATILE * my_free_list; if (n > (size_t) __MAX_BYTES) { malloc_alloc::deallocate(p, n); // n大于128byte,直接调用第一级配置器 return; } my_free_list = free_list + FREELIST_INDEX(n); // 从16个free_list中获取合适的一个 // 调整free_list: 将回收内存区块重新添加到free_list中 q -> free_list_link = *my_free_list; *my_free_list = q; } static void * reallocate(void *p, size_t old_sz, size_t new_sz); } ; // static数据的定义与初值设定 template <bool threads, int inst> char *__default_alloc_template<threads, inst>::start_free = 0; template <bool threads, int inst> char *__default_alloc_template<threads, inst>::end_free = 0; template <bool threads, int inst> size_t __default_alloc_template<threads, inst>::heap_size = 0; template <bool threads, int inst> __default_alloc_template<threads, inst>::obj * __VOLATILE __default_alloc_template<threads, inst> ::free_list[ # ifdef __SUNPRO_CC __NFREELISTS # else __default_alloc_template<threads, inst>::__NFREELISTS # endif ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // The 16 zeros are necessary to make version 4.1 of the SunPro // compiler happy. Otherwise it appears to allocate too little // space for the array. /* We allocate memory in large chunks in order to avoid fragmenting */ /* the malloc heap too much. */ /* We assume that size is properly aligned. */ /* We hold the allocation lock. */ // 为了避免堆中有过多的内存碎片,我们每次申请一大块内存空间 // 我们假定这个空间大小是内存对齐的 template <bool threads, int inst> char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs) { char * result; size_t total_bytes = size * nobjs; size_t bytes_left = end_free - start_free; // 内存池剩余空间大小 if (bytes_left >= total_bytes) { // 内存池剩余空间完全满足需求量 result = start_free; start_free += total_bytes; return(result); } else if (bytes_left >= size) { // 内存池剩余空间满足至少一个区块 nobjs = bytes_left/size; // 调整nobjs的值 total_bytes = size * nobjs; result = start_free; start_free += total_bytes; return(result); } else { // 内存池剩余空间连一个区块都满足不了 // 计算需从堆中申请的内存块大小 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); // 先把内存池剩余空间分配给合适的free_list if (bytes_left > 0) { obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left); ((obj *)start_free) -> free_list_link = *my_free_list; *my_free_list = (obj *)start_free; } start_free = (char *)malloc(bytes_to_get); // 从堆中申请内存,补充内存池 if (0 == start_free) { // 申请内存失败 int i; obj * __VOLATILE * my_free_list, *p; // Try to make do with what we have. That can't // hurt. We do not try smaller requests, since that tends // to result in disaster on multi-process machines. // 先尝试检查我们手上(free_list)拥有的东西。这不会造成伤害。 // 我们不打算检查比size更小的区块,因为那在多进程机器上容易导致灾难。 for (i = size; i <= __MAX_BYTES; i += __ALIGN) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (0 != p) { // 存在未用区块 // 释放该未用区块 *my_free_list = p -> free_list_link; start_free = (char *)p; end_free = start_free + i; return(chunk_alloc(size, nobjs)); // 递归调用自己,重新分配 // Any leftover piece will eventually make it to the // right free list. // 任何内存池剩余空间终将被编入适当的free list } } // 55,山穷水尽了 end_free = 0; // 调用第一级配置器,看看内存不足处理函数能不能起作用 start_free = (char *)malloc_alloc::allocate(bytes_to_get); // This should either throw an // exception or remedy the situation. Thus we assume it // succeeded. // 要么抛出异常,要么内存不足的情况得以改善,我们假定它成功了 } heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return(chunk_alloc(size, nobjs)); // 递归调用自己,重新分配 } } /* Returns an object of size n, and optionally adds to size n free list.*/ /* We assume that n is properly aligned. */ /* We hold the allocation lock. */ // 返回一个大小为n的指针对象,并且有可能会为适当的free list增加节点 // 假定n已经适当调整到8的倍数了 template <bool threads, int inst> void* __default_alloc_template<threads, inst>::refill(size_t n) { int nobjs = 20; // 缺省取得20个新节点 char * chunk = chunk_alloc(n, nobjs); obj * __VOLATILE * my_free_list; obj * result; obj * current_obj, * next_obj; int i; if (1 == nobjs) return(chunk); // 只获得一个节点,直接返回 // 否则准备调整free list,纳入新节点 my_free_list = free_list + FREELIST_INDEX(n); // 找到合适的free list /* Build free list in chunk */ // 纳入新节点 result = (obj *)chunk; *my_free_list = next_obj = (obj *)(chunk + n); for (i = 1; ; i++) { 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); } template <bool threads, int inst> void* __default_alloc_template<threads, inst>::reallocate(void *p, size_t old_sz, size_t new_sz) { void * result; size_t copy_sz; if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES) { return(realloc(p, new_sz)); // 疑问:这里怎么不直接调用第一级配置器里面的realloc } if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p); result = allocate(new_sz); copy_sz = new_sz > old_sz? old_sz : new_sz; memcpy(result, p, copy_sz); deallocate(p, old_sz); return(result); } typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc; typedef __default_alloc_template<false, 0> single_client_alloc;总结: