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是什么,查了下就是一个和仿函数差不多 ...
随机推荐
- Sql Server中的游标最好只用于有主键或唯一键的表
游标cursor,我想大多数人都在sql server里面用过.当一个表数据量不太大的时候,游标还是可以用的,毕竟游标是循环一个表中每一行数据的最简便办法.但是如果你用一个游标去循环一个没有主键或唯一 ...
- /etc/resolv.conf服务器客户端DNS重要配置文件
DNS客户端配置文件:etc/resolv.conf /etc/resolv.conf文件相当于windows如下图: 当然/etc/resolv.conf文件为辅助配置DNS文件,其实在网卡里也可以 ...
- python基础学习9----深浅拷贝
数据类型有可变类型和不可变类型 不可变类型:整型,长整型,浮点数,复数,布尔,字符串,元组 可变类型:列表,字典 浅拷贝 简单说只对第一层进行拷贝,如下对于列表中的列表的数据进行改变,list1和li ...
- Linux之/etc/fstab文件讲解
/etc/fstab是用来存放文件系统的静态信息的文件.位于/etc/目录下,可以用命令less /etc/fstab 来查看,如果要修改的话,则用命令 vi /etc/fstab 来修改.当系统启动 ...
- Dalvik指令备忘
跳转指令 if-eq vx, vy, 目标 如果vx == vy注2,跳转到目标.if-ne vx,vy, 目标 如果vx != vy注2,跳转到目标. if-lt vx,vy, 目标 如果vx &l ...
- 小程序报错数据传输长度为 xxx 已经超过最大长度 xxx
这个错误通常在通过base64给images赋值时发生,setData()微信设置的一次最大传输长度为1M,所有如果编码后的base64字符串长度超过了1M就会报这个错误. 如何解决? 我们可以采取曲 ...
- Spring AOP示例代码
public interface CustomerDao { public void save(); public void update(); } public class CustomerDaoI ...
- 【转】给网站添加X-UA-Compatible标签
X-UA-Compatible是神马? X-UA-Compatible是IE8的一个专有<meta>属性,它告诉IE8采用何种IE版本去渲染网页,在html的<head>标签中 ...
- JavaScript模块化思想之入门篇
在写正文之前先写一点废话,从我大三下学期正式接触前端到现在,已经六个月了.自己从HTML,CSS,简单的JS验证开始,一点点开始走入前端的世界.越发的感觉前端这一领域散发着无穷的魅力,也许这和我真心喜 ...
- day63
一.环境搭建 1.安装node 去官网下载node安装包 傻瓜式安装 万一安装后终端没有node环境,要进行node环境变量的配置(C:\Program Files\nodejs) 可以通过node提 ...