STL源码分析阅读-------std allocator

STL源码分析的第二章讲了STL的内存配置方面的内容,现将有关内存配置器的主线罗列如下:


一般我们用STL,模板的第二个参数(内存配置器),都是用默认的<class Alloc=alloc>,其中alloc支持2种内存的分配方式,alloc的定义如下:


1、配置器定义

#ifdef __USE_MALLOC

typedef __malloc_alloc_template<0> malloc_alloc

typedef malloc_alloc alloc

#else

typedef __default_alloc_template<0,0> alloc

#endif


这里分了2种配置器__malloc_alloc_template和__default_alloc_template,__malloc_alloc_template记为第一级配置器,__default_alloc_template记为第二级配置器。

alloc要么是第一级配置器要么是第二级配置器,这在编译时就指定了。


2、当分配大于128字节的内存时调用第一级配置器,内部实现为直接调用malloc分配内存。

模板形式:

template <int inst>

class __malloc_alloc_template{

...

}

其中int型模板参数没有意义。


3、而分配小于128字节则调用第二级配置器,这个第二级配置器就是一个内存池管理器,里面维护着16种大小(8,16,24,32,...,128字节)的内存块链表,当第二级配置器不能分配内存时会转而调用第一级配置器来分配内存。

备注:其实第二级配置器最终也是malloc内存的,那么都是malloc内存,第二级malloc不了内存难道第一级就能malloc吗,答案是也不行。不过第一级配置器分配不了时会调用一个回调,就和c++的new的handler回调一样,期望程序员去释放其他内存来满足需求,这就是区别。


模板形式

template <bool threads,int inst>

class __default_alloc_template{

...

}


初始时内存块链表为空,每次分配内存的时候,按照这16种大小进行分配,而且一次也不是只分配一块,可能一次分配多块,比如你申请16字节内存,系统可能会一次分配10个16字节的内存,链接到内存链表,然后取一个给你,某一种大小类型的内存按如下结构链接:

union obj{
union obj* free_list_link;
char client_data[1];
};

所有这16种大小的类型内存用一个表格表示:

enum{__ALIGN=8};
enum{__MAX_BYTES=128};
enum{__NFREELISTS=__MAX_BYTES/__ALIGN};

static obj* volatile free_list[__NFREELISTS];


        裸内存的分配由函数chunk_alloc来管理,裸内存使用如下结构表示:

static char* start_free;
static char* end_free;
static size_t heap_size;
 


start_free表示上次分配的未链接到free_list的内存起始地址

start_free表示上次分配的未链接到free_list的结束起始地址

heap_size表示总分配大小


有几点需要注意

第一、一次分配内存是大于你所需要的内存的,代码:size_t bytes_to_get = 2*total_bytes+ROUND_UP(heap_size>>4);

total_bytes表示你需要的内存,bytes_to_get表示系统分配的内存,分配完了链入free_list,从代码可以看出,一次分配是有未链接入free_list的内存,由start_free定这个起始位置。

第二、如果裸内存剩余内存start_free满足不了你需要的大小,系统会先将这点点剩余链接入空闲内存链表free_list,然后再来malloc新的内存给你用。

第三、如果malloc不出你需要的内存时,会先扫描free_list看这里面有没有满足你需要的内存。

第四、都没有,抛出std::bad_alloc异常。


随着内存的分配,内存块链表越来越大,当释放内存的时候,内存并没有归还系统,而是将此块内存作为空闲块又链入空闲内存块链表,方法是将这块内存转成obj类型,设置 free_list_link指针指向原来的空闲链表头,即将此块内存合并进了空闲内存链表。


4、容器内部的内存分配,统一使用simple_alloc来分配,simple_alloc定义如下:

template <class T, class Alloc>

class simple_alloc{

public:

//下面这4个接口就是所有容器使用的内存管理的接口

static T* allocate(size_t n) { return 0==n?0:(T*)Alloc::allocate(n*sizeof(T);}

static T* allocate(void) {...}

static void deallocate(T* p, size_t n) {...}

static void deallocate(T* p){}

}

由此看出simple_alloc的内存分配有Alloc指定,Alloc由各个容器自己指定


5、容器内部,比如vector

template vector<class T, class Alloc=alloc>

class vector{

typedef simple_alloc<T,Alloc> data_allocator;

...

}

看出容器使用alloc这个配置器进行内存的管理,而这个alloc由第1条的宏定义定义了到底使用第一级配置还是第二级配置器。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值