stl源码分析之allocator
allocator封装了stl标准程序库的内存管理系统,标准库的string,容器,算法和部分iostream都是通过allocator分配和释放内存的。标准库的组件有一个参数指定使用的allocator类,比如vector的原型是:
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
第二个参数_Alloc指定使用的allocator,默认是std::allocator。我们也可以自己指定allocator
vector<int, __gnu_cxx::malloc_allocator<int> > malloc_vector;
将使用malloc_allocator分配释放内存。
GNU gcc实现了多种allocator,下面简单介绍几种allocator的作用,我的g++版本是4.8。
1. new_allocator
这是g++4.8默认使用的allocator,即 std::allocator使用的allocator,在头文件
/usr/include/c++/4.8/bits/allocator.h中定义了 std::allocator:
template<typename _Tp>
class allocator: public __allocator_base<_Tp>
std::allocator使用的接口是由__allocator_base定义的,而后者在/usr/include/i386-linux-gnu/c++/4.8/bits/c++allocator.h定义为new_allocator:
# define __allocator_base __gnu_cxx::new_allocator
new_allocator只是简单地包装::operator new和operator delete,实现在/usr/include/c++/4.8/ext/new_allocator.h
pointer allocate(size_type __n, const void* = )
{
if (__n > this->max_size())
std::__throw_bad_alloc();
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
void deallocate(pointer __p, size_type)
{ ::operator delete(__p); }
并没有memory pool,所以现在如果还有程序因为使用了stl而出现内存没有回收的问题,那么一定是libc的cache没有释放,并不是stl的原因。
2. malloc_allocator
malloc_allocator直接包装malloc和free,定义在/usr/include/c++/4.8/ext/malloc_allocator.h头文件中,
pointer allocate(size_type __n, const void* = )
{
if (__n > this->max_size())
std::__throw_bad_alloc();
pointer __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp)));
if (!__ret)
std::__throw_bad_alloc();
return __ret;
} void deallocate(pointer __p, size_type)
{ std::free(static_cast<void*>(__p)); }
3. array_allocator
array_allocator并不调用new或者malloc从操作系统申请分配内存,而是直接使用已分配的内存。通过使用该allocator可以重用内存,效率很高。
array_allocator(array_type* __array = ) _GLIBCXX_USE_NOEXCEPT
: _M_array(__array), _M_used(size_type()) { }
Pointer allocate(size_type __n, const void* = )
{
if (_M_array == || _M_used + __n > _M_array->size())
std::__throw_bad_alloc();
pointer __ret = _M_array->begin() + _M_used;
_M_used += __n;
return __ret,_M_used
}
_M_array指向已分配的内存块地址,_M_used指向空闲的地址位移,初始值为0,每分配一段内存后就将_M_used后移.当需要的内存量超出空闲内存大小时会抛出bad_alloc异常。
4. debug_allocator
可以包装任意其它的allocator,包括G++自带的或者用户自定义的,分配内存时多分配了一块内存保存申请的内存大小,释放时检查释放的内存大小是否和保存的值一样,不一样则抛出异常。具体的申请释放动作由被包装的allocator执行。
pointer allocate(size_type __n)
{
pointer __res = _M_allocator.allocate(__n + _M_extra);
size_type* __ps = reinterpret_cast<size_type*>(__res);
*__ps = __n;
return __res + _M_extra;
}
void deallocate(pointer __p, size_type __n)
{
if (__p)
{
pointer __real_p = __p - _M_extra;
if (*reinterpret_cast<size_type*>(__real_p) != __n)
{
throw std::runtime_error("debug_allocator::deallocate wrong size");
}
_M_allocator.deallocate(__real_p, __n + _M_extra);
}
else
throw std::runtime_error("debug_allocator::deallocate null pointer");
}
__ps中存储了当前申请分配的内存长度, deallocate时会检测释放的内存大小是否等于该值。debug_allocator可以检测内存是否存在泄露,代价是需要多分配用于debug的空间。
5. __pool_alloc
唯一一个带内存池的allocator,也是G++早期默认使用的allocator,侯捷的《stl源码剖析》第二章详细分析了其代码实现.原理就是为了减少内存碎片,当分配大于128byte的内存时直接调用operator new,而小于128byte的内存则从一个free list里面取,free list中的内存是可以重用的,程序运行期间不会归还给操作系统。过程比较复杂,有兴趣的同学可以参考《stl源码剖析》。
stl源码分析之allocator的更多相关文章
- STL源码分析读书笔记--第二章--空间配置器(allocator)
声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...
- STL源码分析《4》----Traits技术
在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...
- STL源码分析《3》----辅助空间不足时,如何进行归并排序
两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在 ...
- STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort
最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...
- STL 源码分析六大组件-allocator
1. allocator 基本介绍 分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放.C ++标准库提供了默认使 ...
- STL源码分析与实现-stl_list容器
1. stl_list 介绍 今天我们来总结一下stl_List, 通过之前介绍单链表的文章,其实对链表的基本操作已经十分熟悉了,那对于stl_list,无非就是链表结构不一样,至于其中的增删改查的细 ...
- STL 源码分析《2》----nth_element() 使用与源码分析
Select 问题: 在一个无序的数组中 找到第 n 大的元素. 思路 1: 排序,O(NlgN) 思路 2: 利用快排的 RandomizedPartition(), 平均复杂度是 O(N) 思路 ...
- STL源码分析之迭代器
前言 迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *和operator-&g ...
- stl源码分析之list
本文主要分析gcc4.8版本的stl list的源码实现,与vector的线性空间结构不同,list的节点是任意分散的,节点之间通过指针连接,好处是在任何位置插入删除元素都只需要常数时间,缺点是不能随 ...
随机推荐
- Css3 实现丝带效果
代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- ChakraCore ,Net托管编程
前言 有些有着复杂业务逻辑的应用程序,需要为用户提供高度自定化的功能.比如像Word中的宏,当然可以自己设计一套简易的脚本解析引擎,但考虑通用性,成熟度,其实选择一款JS脚本引擎,直接嵌入到应用系统中 ...
- ubuntu使用----高效快捷键
桌面快捷键 : ALT + F1: 聚焦到桌面左侧任务导航栏,可按上下键导航. ALT + F2: 运行命令 ALT + F4: 关闭窗口 ALT + TAB: 切换程序窗口 ALT + 空格: 打开 ...
- C# 缓存工厂类
描 述:缓存工厂类 /// <summary> /// 描 述:缓存工厂类 /// </summary> public class CacheFactory { /// < ...
- 苹果IPad客户端安装测试软件
背景: 公司在开发一个App应用,需要部署在苹果IPad上进行测试,但是我负责后端开发对安装及测试相关流程不了解.经过一番学习得出以下结论: 1. 首先申请一个苹果的开发账号(一千块左右),大约能注册 ...
- 由使用request-promise-native想到的异步处理方法
由使用request-promise-native想到的异步处理方法 问题场景 因为js语言的特性,使用node开发程序的时候经常会遇到异步处理的问题.对于之前专长App开发的我来说,会纠结node中 ...
- 转:介绍几个著名的实用的Java反编译工具,提供下载
from :http://www.glorze.com/219.html 反编译 众所周知,我们将源代码进行编译,生成可执行的程序或者容器发布包,这个将代码转换的过程就是编译的过程,而反编译就是将这些 ...
- 19-3-7Python中小数据池、数据类型的补充、set集合
一.小数据池(了解) “id” 获取内存地址 “==” 比较等号两端的值是否相等 “is” 身份运算:判断的是两个对象的内存地址是否相同. 代码块:一个文件就是一个代码块.(函数.类都是 ...
- Windows8系统下设置Mongodb开机启动
1. 官网下载安装 MongoDB https://www.mongodb.com/ 2. 环境变量设置 把 mongod.exe 所在路径加入到环境变量的PATH, 我这里安装的路径是 D:\db\ ...
- 用启动器py成功解决python2和python3同时共存且同时运行的问题
缘起:之前一直用PHP来开发微信公众号后台,最近正在学习python,而且看到微信官方也把公众号后台的示例代码换成了python的,但是示例中用的web.py需要用到python2,而我自己的电脑上装 ...