-
示意图
-
stl源码
// 摘自gcc-2.95.1
union _Obj {
union _Obj* _M_free_list_link;
char _M_client_data[1]; /* The client sees this. */
};
# ifndef __SUNPRO_CC
enum {_ALIGN = 8};
enum {_MAX_BYTES = 128};
enum {_NFREELISTS = _MAX_BYTES/_ALIGN};
# endif
// 传入bytes字节,返回(bytes + 7)/7字节,即bytes除8向上取整。
static size_t _S_freelist_index(size_t __bytes)
{
return (((__bytes) + _ALIGN-1)/_ALIGN - 1);
}
// 传入bytes字节,返回bytes + 7 - (bytes + 7)% 7,即所需要的8字节的整数倍。
static size_t _S_round_up(size_t __bytes)
{
return (((__bytes) + _ALIGN-1) & ~(_ALIGN - 1));
}
// 分配空间的函数
static void* allocate(size_t __n)
{
// 存储指针的链表,指针指向实际存储空间。
_Obj* __VOLATILE* __my_free_list;
_Obj* __RESTRICT __result;
// 如果需要分配的字节大于128字节,直接调用malloc
if (__n > (size_t) _MAX_BYTES) {
return(malloc_alloc::allocate(__n));
}
// 找到链表指定下标的指针
__my_free_list = _S_free_list + _S_freelist_index(__n);
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
# ifndef _NOTHREADS
/*REFERENCED*/
_Lock __lock_instance;
# endif
// 取出指定指针的指针,默认为0
__result = *__my_free_list;
if (__result == 0) {
// 如果指针为空,调用分配空间的函数,返回指向头节点的指针
void* __r = _S_refill(_S_round_up(__n));
return __r;
}
*__my_free_list = __result -> _M_free_list_link;
return (__result);
}
template <bool __threads, int __inst>
void*
__default_alloc_template<__threads, __inst>::_S_refill(size_t __n)
{
int __nobjs = 20;
// 将分配的空间分为20个大小为_n字节的节点
char* __chunk = _S_chunk_alloc(__n, __nobjs);
_Obj* __VOLATILE* __my_free_list;
_Obj* __result;
_Obj* __current_obj;
_Obj* __next_obj;
int __i;
// 当指向空闲链表的头节点时
if (1 == __nobjs) return(__chunk);
__my_free_list = _S_free_list + _S_freelist_index(__n);
/* 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 -> _M_free_list_link = 0;
break;
} else {
__current_obj -> _M_free_list_link = __next_obj;
}
}
return(__result);
}
template <bool __threads, int __inst>
char*
__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size,
int& __nobjs)
{
char* __result;
size_t __total_bytes = __size * __nobjs;
size_t __bytes_left = _S_end_free - _S_start_free;
if (__bytes_left >= __total_bytes) {
__result = _S_start_free;
_S_start_free += __total_bytes;
return(__result);
} else if (__bytes_left >= __size) {
__nobjs = (int)(__bytes_left/__size);
__total_bytes = __size * __nobjs;
__result = _S_start_free;
_S_start_free += __total_bytes;
return(__result);
} else {
size_t __bytes_to_get =
2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
// Try to make use of the left-over piece.
if (__bytes_left > 0) {
_Obj* __VOLATILE* __my_free_list =
_S_free_list + _S_freelist_index(__bytes_left);
((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
*__my_free_list = (_Obj*)_S_start_free;
}
_S_start_free = (char*)malloc(__bytes_to_get);
if (0 == _S_start_free) {
size_t __i;
_Obj* __VOLATILE* __my_free_list;
_Obj* __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.
for (__i = __size; __i <= _MAX_BYTES; __i += _ALIGN) {
__my_free_list = _S_free_list + _S_freelist_index(__i);
__p = *__my_free_list;
if (0 != __p) {
*__my_free_list = __p -> _M_free_list_link;
_S_start_free = (char*)__p;
_S_end_free = _S_start_free + __i;
return(_S_chunk_alloc(__size, __nobjs));
// Any leftover piece will eventually make it to the
// right free list.
}
}
_S_end_free = 0; // In case of exception.
_S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
// This should either throw an
// exception or remedy the situation. Thus we assume it
// succeeded.
}
_S_heap_size += __bytes_to_get;
_S_end_free = _S_start_free + __bytes_to_get;
return(_S_chunk_alloc(__size, __nobjs));
}
}
标签:__,Obj,bytes,list,free,分配器,allocator,size
From: https://www.cnblogs.com/skycrash/p/17494183.html