stl源码剖析 详细学习笔记 空间配置器
//---------------------------15/04/05----------------------------
/*
空间配置器概述:
1:new操作包含两个阶段操作
1>调用::operator new配置内存(底层使用malloc来申请内存)。
2>调用函数的构造函数,构造对象内容。
delte和new一样,先调用析构函数,再调用::operator delete释放内存。
2:为了效率,stl把两个阶段分开来。
1>内存配置操作: alloc::allocate();
2>内存释放操作: alloc::deallocate();
3>对象构造操作: ::construct();
4>对象析构操作: ::destory();
3:内存配置器的整体:
1><stl_construct.h> : 这里定义了全局函数construct()和的destroy()。
2><stl_alloc.h> : 定义了一二级配置器。
3><stl_uninitialized.h> : 定义了一些全局函数,用来填充或复制大块内存数据。
un_initialized_copy(), un_initialized_fill(), un_initialized_fill_n()
这些函数对效率考虑得面面俱到:最差的情况下会调用construct(),最佳的情况下会
使用c的标准函数memmove()直接进行内存数据的移动。
*/
//construct() 和 destroy()
template<class T1,
class T2>
inline
void construct(T1* p,
const T2& value)
{
new (p) T1(value);
}
template<class T>
inline
void destroy(T* pointer)
{
pointer->~T();
}
template<class ForwardIterator>
inline
void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
template<class ForwardIterator,
class T>
inline
void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
template<class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for(; first < last; ++first)
destroy(&*first);
}
template<class ForwardIterator>
inline
void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
inline
void destroy(char*,
char*) {}
inline void destroy(wchar_t*,
wchar_t*) {}
//alloc
template<class T,
class Alloc>
class simple_alloc
{
public:
static T* allocate(size_t n)
{
== n ?
: (T*) Alloc::allocate(n *
sizeof(T));
}
static T* allocate(void)
{
return (T*) Alloc::allocate(sizeof(T));
}
static void deallocate(T *p, size_t n)
{
!= n)
Alloc::deallocate(p, n *
sizeof(T));
}
static void deallocate(T *p)
{
Alloc::deallocate(p,
sizeof(T));
}
};
//第一级配置
template<int inst>
class __malloc_alloc_template
{
private:
static void* oom_malloc(size_t);
static void* oom_realloc(void *, size_t);
static void (* __malloc_alloc_oom_handler)();
public:
//直接调用malloc分配内存,失败就调用oom_malloc,这个函数会不断申请分配,
//并不断调用处理函数,如果没有处理函数,就抛出错误。
static void* allocate(size_t n)
{
void *result = malloc(n);
== result)
result == oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t)
{
free(p);
}
static void* reallocate(void *p, size_t, size_t new_sz)
{
void *result = realloc(p, new_sz);
== result)
result = oom_realloc(p, new_sz);
return result;
}
static void (* set_malloc_handle(void (*f)()))()
{
void ( *old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
};
template<int inst>
void ( *__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() =
;
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;
== my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = malloc(n);
if(result)
return (result);
}
}
template<int inst>
void* __malloc_alloc_oom_handler<int>::oom_realloc(void *p, size_t n)
{
void ( *my_malloc_handler());
void *result;
for(; ;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
== my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = realloc(p, n);
if(result)
return (result);
}
}
> malloc_alloc;
//第二级配置器
//使用union节省空间
union obj
{
union obj * free_list_link;
];
};
enum { __ALIGN =
};
enum { __MAX_BYTES =
};
enum { __NFREELISTS = __MAX_BYTES / __ALIGN};
template<bool threads,
int inst>
class __default_alloc_template
{
private:
//这里就是加7再对8取模
这样写的公式扩展性比较小, 也就是__ALIGN必须取2的倍数,
//不然这公式就不是取模操作了。
static size_t ROUND_UP(size_t bytes)
{
) & ~(__ALIGN - ));
}
union obj
{
union obj *free_list_link;
];
};
static obj * volatile free_list[__NFREELISTS];
static size_t FREELIST_INDEX(size_t bytes)
{
) / __ALIGN - ));
}
static void* refill(size_t n);
static char *chunk_alloc(size_t size,
int &nobjs);
static char *start_free;
static char *end_free;
static size_t heap_size;
public:
static void* allocate(size_t n)
{
obj *
volatile * my_free_list;
obj * result;
if(n > (size_t)__MAX_BYTES)
return (malloc_alloc::allocate(n));
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
)
{
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result->free_list_link;
return (result);
}
//如果比最大大小大,就交给第一级配置,否则收回到链表中
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);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q->free_list_link = *my_free_list;
*my_free_list = q;
}
static void* reallocate(void *p, size_t old_sz, size_t new_sz);
};
template<bool threads,
int inst>
char *__default_alloc_template<threads, inst>::start_free =
;
template<bool threads,
int inst>
char *__default_alloc_template<threads, inst>::end_free =
;
template<bool threads,
int inst>
size_t *__default_alloc_template<threads, inst>::heap_size =
;
template<bool threads,
int inst>
__default_alloc_template<threads, inst>::obj *volatile
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] =
{,
, , , , ,
, , , , ,
, , , , };
template<bool threads,
int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
//20个节点
;
//申请20个节点,会修改nobjs的值,也就是申请到多少个节点
char *chunk = chunk_alloc(n, nobjs);
obj *
volatile * my_free_list;
obj *result;
obj *current_obj, *next_obj;
int i;
//如果只申请到一个节点,直接返回
== nobjs)
return (chunk);
//找到n大小节点的位置
my_free_list = free_list + FREELIST_INDEX(n);
//第一个节点是用来返回的,不用存入链表中
result = (obj*)chunk;
//链表的第一个节点就是下一个节点
*my_free_list = next_obj = (obj*)(chunk + n);
; ; i++)
{
//当前节点是下一个节点
current_obj = next_obj;
//下一个节点是下下个节点
next_obj = (obj*)((char*)next_obj + n);
//如果是最后的节点了,就设置下个节点为0,并返回,否则好设置下一个节点
== i)
{
current_obj->free_list_link =
;
break;
}
else
{
current_obj->free_list_link = next_obj;
}
}
//把申请到的第一个节点返回
return (result);
}
template<bool threads,
int inst>
char* __default_alloc_template<threads, inst>::
chunk_alloc(size_t size,
int& nobjs)
{
char *result;
//需要的总大小(bytes)
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);
}
//如果剩下的大小大于一个size,
就返回最大的内存大小
else if(bytes_left >= size)
{
nobjs = bytes_left / size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return (result);
}
//一个都没有
else
{
//算出需要的内存大小,2倍的需求量+现有大小的1/16(需要调整)。
size_t bytes_to_get =
* total_bytes + ROUND_UP(heap_size >> );
//先把内存池中剩余的空间中的内存取出放入链表中
)
{
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);
== start_free)
{
//无法正常申请内存
int i;
obj *
volatile * my_free_list, *p;
//尝试拆分大节点
for(i = size; i <= __MAX_BYTES; i += __ALIGN)
{
//找到比要申请的内存大一点的节点,可以把他拆分掉
my_free_list = free_list + FREELIST_INDEX(i);
//让p等于这个链表的第一个节点
p = *my_free_list;
!= p)
{
//如果有节点,就把这个节点放入内存池中
*my_free_list = p->free_list_link;
start_free = (char*)p;
end_free = start_free + i;
return (chunk_alloc(size, nobjs));
}
}
//如果找不到大的节点,只能调用第一级配置,调用客户设置的处理函数了。
end_free =
;
start_free = (char*)malloc_alloc::allocate(bytes_to_get);
}
//内存池大小调整
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return (chunk_alloc(size, nobjs));
}
}
stl源码剖析 详细学习笔记 空间配置器的更多相关文章
- stl源码剖析 详细学习笔记 配接器
//---------------------------15/04/03---------------------------- /* 配接器概述: 1:adapter是一种设计模式:将一个clas ...
- stl源码剖析 详细学习笔记 hashtable
//---------------------------15/03/24---------------------------- //hashtable { /* 概述: sgi采用的是开链法完成h ...
- stl源码剖析 详细学习笔记 set map
// // set map.cpp // 笔记 // // Created by fam on 15/3/23. // // //---------------------------15/03 ...
- stl源码剖析 详细学习笔记 RB_tree (1)
// // RB_tree_STL.cpp // 笔记 // // Created by fam on 15/3/21. // // #include "RB_tree_STL.h&q ...
- stl源码剖析 详细学习笔记priority_queue slist
// // priority_queue.cpp // 笔记 // // Created by fam on 15/3/16. // // //------------------------- ...
- stl源码剖析 详细学习笔记heap
// // heap.cpp // 笔记 // // Created by fam on 15/3/15. // // //---------------------------15/03/15 ...
- stl源码剖析 详细学习笔记 算法(1)
//---------------------------15/03/27---------------------------- //算法 { /* 质变算法:会改变操作对象之值 所有的stl算法都 ...
- stl源码剖析 详细学习笔记 算法总览
//****************************基本算法***************************** /* stl算法总览,不在stl标准规格的sgi专属算法,都以 *加以标 ...
- stl源码剖析 详细学习笔记 RB_tree (2)
//---------------------------15/03/22---------------------------- //一直好奇KeyOfValue是什么,查了下就是一个和仿函数差不多 ...
随机推荐
- UIButton vs UIEventListener 事件处理
NGUI的事件 在使用NGUI的事件处理时,发现UIButton和UIEventListener之间的共同点越来越多. 当然处理事件,也有一些其它的函数,比如:UIEventTrigger,Butto ...
- Linux 配置 hosts
1. hosts 是什么 维基百科对 hosts 的介绍如下: hosts文件(域名解析文件)是一个用于储存计算机网络中各节点信息的计算机文件. 这个文件负责将主机名称映射到相应的IP地址. host ...
- MySQL案列之主从复制出错问题以及pt-slave-restart工具的使用
今天主从复制遇到一个问题,主库上插入了几百行万数据,后来又删除了这些数据,原因就是主库删除的表从库中不存在,导致从库在遇到删除不存在表的错误无法继续同步. MySQL [(none)]> sho ...
- /etc/sudoers文件的分析以及sudo的高级用法
高级用法总结: sudo命令是普通用户的提权操作指令.在权限控制中,我们可以使用/etc/sudoers文件中来进行设置.基本的用法比较熟悉.比如设置一个普通用户可拥有root用户的运行权限,那么设置 ...
- 不使用 vue-cli 与 vue 模版,使用 Vue2.x + webpack4.x 从零开始一步步搭建项目框架
说明 这是我根据慕课网上的一个课程 Vue+Webpack打造todo应用 过程一步步搭下来的框架,去掉了业务相关的逻辑. 项目最终的效果包括了引入vue框架:使用CSS预处理器:使用babel:引用 ...
- C++基础算法学习——生理周期
人有体力.情商.智商的高峰日子,它们分别每隔23天.28天和33天出现一次.对于每个人,我们想知道何时三个高峰落在同一天.给定三个高峰出现的日子p,e和i(不一定是第一次高峰出现的日子),再给定另一个 ...
- October 13th 2017 Week 41st Friday
The shortest distance between two people is a smile. 人与人之间最短的距离是微笑. I find a smiling face can bring ...
- css常见知识点
1.内核区分 希望某一个浏览器能一统江湖 -ms-transform:rotate(7deg); //-ms代表ie内核识别码 -moz-transform:rotate(7deg); //-moz代 ...
- Gitkraken的使用
一个优秀的团队合作离不开git,一个优秀的程序员也离不开git.gitkraken是我在进行软工实践这门课接触到的git的UI界面的工具,它给我留下的印象就是非常好用和方便 怎么个方便法呢? 方便的安 ...
- post-message-stream的学习-metamask
kumavis/post-message-stream post-message-stream Sets up a duplex object stream over window.postMessa ...