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是什么,查了下就是一个和仿函数差不多 ...
随机推荐
- js经典应用
一.js字符串转数字: 1.parseInt()和parseFloat()两个转换函数: 2.强制类型转换,Number(value)——把给定的值转换成数字(可以是整数或浮点数): 3.利用js变量 ...
- October 17th 2017 Week 42nd Tuesday
We execuse our sloth under the pretext of difficulty. 我们常以困难为由,作为懒惰的借口. The process of my system-tra ...
- C#中单问号(?)和双问号(??)的用法整理
1.单问号(?) 1.1 表示Nullable类型 C#2.0里面实现了Nullable数据类型 //A.比如下面一句,直接定义int为null是错误的,错误提示为无法将null转化成int,因为后者 ...
- Pre标签 自动换行
<pre> 元素可定义预格式化的文本.被包围在 pre 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre> 标签的一个常见应用就是用来表示计算机的源代码 ...
- 在Linux服务器上运行Jupyter notebook server教程
在Linux服务器上运行Jupyter notebook server教程 很多deep learning教程都推荐在jupyter notebook运行python代码,方便及时交互.但只在本地运行 ...
- 实例化list
List<String> lists = new ArrayList<String>();list.add("123");
- 在Word2007,2010,2016中分栏但不换页的方法
解决方法: word2007:界面左上角的按钮->选择word选项->依次点击“高级”->“版式选项”->点开加号,“按word6.x/95/97的方式排放脚注”. Word2 ...
- 2-5 R语言基础 factor
#因子:分类数据#有序和无序#整数向量+标签label#Male/Female#常用于lm(),glm() > x <- factor(c("female"," ...
- NOIP模拟赛-2018.10.22
模拟赛 今天第一节课是历史,当然是不可能上的,一来到机房发现今天高二考试... 老师说以后可能还要给高一考...那还不如现在跟着做好了,毕竟在学长学姐中垫底显得没那么丢人 这套题风格挺奇怪的...为什 ...
- Docker实战(二)之操作Docker容器
容器是Docker的另外一个核心概念.简单来说,容器是镜像的一个运行实例.所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层.如果认为虚拟机是模拟运行的一整套操作系统系统(包括内核,应 ...