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是什么,查了下就是一个和仿函数差不多 ...
随机推荐
- SQLSERVER中的鬼影索引
SQLSERVER中的鬼影索引 看这篇文章之前可以先看一下鬼影记录 了解了解一下SQLSERVER里的鬼影记录关于鬼影记录的翻译一关于鬼影记录的翻译二 当删除表中的某一条记录的时候,索引页面的对应记录 ...
- jdk1.8配置环境变量
1. 准备好jdk安装文件,选择地址,假设使用默认地址 2. 安装jdk,此时跳出安装 jre 的地址 3. 等待安装 4.找到安装路径,选择jdk 5. 复制文件夹下的bin 6. 点击我的电脑右键 ...
- jQuery为元素设置css的问题
例子: 有如下的html代码 对文本框设置字体大小为20px ,即font-size:20px 首先会想到如下: $('input').css({font-size:'20px'}); 由于属性不能使 ...
- 转:SQL中 patindex函数的用法
语法格式:PATINDEX ( '%pattern%' , expression ) 返回pattern字符串在表达式expression里第一次出现的位置,起始值从1开始算. pattern字符串在 ...
- windows的一些好用命令-自己总结:
在win+R运行框中: cmd:进入命令行界面 msconfig:可以查看“系统配置” msinfo32:查看系统信息 services.msc打开"服务&q ...
- 【Alpha 冲刺】 5/12
今日任务总结 人员 今日原定任务 完成情况 遇到问题 贡献值 胡武成 建立数据库 未完成 设计表结构的时候,有些逻辑没有设计好,重新review一番设想的功能才初步确定表结构 孙浩楷 根据UI设计, ...
- [BUG]自己的bug自己解,记一次在变量使用过程引发的bug
[实现的功能要求]在短信编辑界面,将所有的emoji表情全部插入到编辑区域,其中表情共有5页,每遍历完一页时需要自动翻页重新获取表情并插入,在第5页中只有10个表情 下面先看看这段代码,大家能否看出有 ...
- 深入学习css之background属性
css中允许应用纯色作为背景,也允许使用图片作为背景. background一共有8个对应的属性: 1.background-color:颜色值 用于设定背景的颜色 有3种定义颜色的形式, 1, 颜色 ...
- 自带hyper -v 或者 Vmware安装Linux centos
centos系统存在网盘,链接: https://pan.baidu.com/s/1A5ywyLjIegcftaT_xCvPbA 密码: n6v4 https://blog.csdn.net/nanc ...
- [C++] set与multiset的常用函数
参考资料:[C++ STL]Set和Multiset set 与 multiset set不允许重复 multiset允许重复 例: set : 1 2 3 4 5 6 multiset : 1 2 ...