空间配置器
空间配置器: 用来分配内存。它并不会给我们直接使用,而是在容器之后默默工作。
在c++中,一般使用new
在c++中,一般使用new来来分配内存,同时并调用构造函数来完成值得初始化,但在stl中,这两步是分开的
首先有空间配置器来分配内存,然后调用construct函数来完成在指定内存完成值得初始化。
构造可以调用place new 来在指定的内存空间来声明对象,和初始化值。但是毕竟类才需要调用构造,
有的对象并不需要使用构造函数。使用简单的内存拷贝就能达到目的。
sgi中使用的默认的空间配置器是alloc。 alloc有两种不同的方式来分配内存。当所申请的空间大于128B的时候
直接调用c语言中的malloc来来申请内存, free来释放内存,而小于128B的空间,就在内存池中分配。
空间配置器标准接口
1 | allocator::value_type |
sgi中的空间配置器
sgi中使用alloc作为默认的空间配置器,但是该配置器并不真正符合标准接口。但是sgi中是默认使用alloc的
在sgi中:
stl_construct.h 定义了construct()和destroy()
stl_alloc.h 定义了一二级空间配置器,名为alloc
stl_uninitialized.h 定义了一些全局函数用来填充或者复制内存数据。
stl_initialized_copy
stl_initialized_fill()
stl_initialized_fill_n()
construct()和destroy()
1 | template <class T1, class T2> |
一级空间配置器
一级空间配置器__malloc_alloc_template
一级空间配置器直接使用了c中的malloc() free() realloc()
1 | template <int inst> |
二级空间配置器
__default_alloc_template
二级空间配置器采用的是内存池的方式。
先自动将申请的空间拓展到8的倍数。
二级空间配置器8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128
1 | class __default_alloc_template { |
allocate
1 | static void * allocate(size_t n) |
deallocate
1 | static deallocate(size_t n) |
refill函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30template <bool threads, int inst>
void * __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = 20;
//chunk_alloc从内存池中申请内存。
char * chunk = chunk_alloc(n, nobjs);
obj *volatile *my_free_list;
obj *result;
obj *current_obj, *next_obj;
//如果只获得一个区块,这个却快就分配给调用者用,free_list无新节点
if (1 == nobjs) return (chunk);
//否则调整free_list,插入新的节点
my_free_list = free_list + FREELIST_INDEX(n);
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->free_list_link = 0;
break;
} else {
current_obj->free_list_link = next_obj;
}
}
return (result);
}
内存池管理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::
chunk_alloc(size_t size, int &nobjs)
{
char *result;
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free;
if (bytes_left >= total_bytes) {
//内存池中剩余的内存能够分配nobjs个节点
result = start_free;
start_free += total_bytes;
return (result);
} else if (bytes_left >= size) {
//内存池中的剩余空间不能分配所有,但是能够分配一个以上
nobjs = bytes_left / size;
total_bytes = size * nobjs;
result = start_size;
start_free += total_bytes;
return (result);
} else {
//内存池中的内存不够分配一个
//计算接下来要分配的空间大小 需求的两倍加上
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if (bytes_left > 0) {
//把剩下的零头分配给合适的free_list
obj * volatile *my_free_list = free_list + FREELIST_INDEX(bytes_left);
//调整free_list 将剩余的空间插入到空闲的链表
((obj *)start_free)->free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get)
}
}
内存基本处理工具
uninitialized_copy
将first和last之间的元素拷贝到result开始的空间。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22template <class InputIterator, class ForwardIterator>
ForwardIterator
uninitialized_copy(InputIterator first, InputIterator last,
ForwardIterator result)
{
typedef typename __type_traits<T>::is_POD_type is_POD;
return __uninitialized_copy_aux(first, last, result, is_POD());
}
template <class InputIterator, class ForwardIterator>
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__true_type) {
copy(first, last, result);
}
template <class InputIterator, class ForwardIterator>
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__false_type) {
for (; first != last; ++first, ++cur)
construct(&*cur, *first);
return cur;
}
当迭代器所指向的对象为true_type 就直接调用函数来进行拷贝,否则需要对每个元素进行构造
uninitialized_fill
将first到last之间的元素以x来初始化
通过萃取出迭代器所指向元素的值得类型来作出不同的操作
true_type直接调用函数fill,false_type需要分别调用每个的构造函数
同时对char和wchar_t 类型分别生成特别的版本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39template <class ForwardIterator, class T>
void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x)
{
__unitialalized_fill(first, last, x, value_type(first));
}
template <class ForwardIterator, class T, class T1>
inline void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x, T1*) {
typedef typename __type_traits<T1>::is_POD_type is_POD();
__uninitialized_fill_aux(first, last, x, is_POD());
}
template <class ForwardIterator, class T>
inline void
__uninitialized_fill_aux(ForwardIterator first, ForwardIterator last,
const T&x, __true_type)
{
fill(first, last, x);
}
template <class ForwardIterator, class T>
void
__uninitialized_fill_aux(ForwardIterator first, ForwardIterator last,
const T& x, __false_type)
{
ForwardIterator cur = first;
for (; cur != last; ++cur)
construct(&*cur, x);
}
//针对char 和wchar_t的特化版本,直接调用memmove函数
inline char* uninitialized_copy(const char *first, const char* last,
char * result) {
memmove(result, first, last - first);
return result + (last - first);
}
inline wchar_t* uninitialized_copy(const wchar_t *first, const wchar_t *last,
wchar_t* result) {
memmove(result, first, sizeof(wchar_t) * (last - first));
return result + (last - first);
}
uninitialized_fill_n
该函数的作用:
将迭代器first之后n个单元初始化为x。
通过萃取出迭代器所指向元素的值得类型来作出不同的操作。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27template <class ForwardIterator, class Size, class T>
ForwardIterator
uninitialized_fill_n(ForwardIterator first, Size n, const T &x)
{
return __uninitialized_fill_n(first, n, x, value_type(first));
}
template <class ForwardIterator, class Size, class T>
inline ForwardIterator __unitiallized_fill_n(ForwardIterator first, Size n,
const T& x, T1 *)
{
typedef typename __type_traits<T1>::is_POD_type is_POD;
return __uninitialized_fill_n_aux(first, n, x, is_POD());
}
template <class ForwardIterator, class Size, class T>
inline ForwardIterator
__unitialized_fill_n_aux(ForwardIterator first, Size n,
const T& x, __true_type) {
return fill_n(first, n, x);
}
template <class ForwardIterator, class Size, class T>
inline ForwardIterator
__unitialized_fill_n_aux(ForwardIterator first, Size n,
const T& x, __false_type) {
for ( ; n > 0; --n, ++cur)
construct(&*cur, x);
return cur;
}