C++ STL学习之 空间配置器(allocator)
众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间)分配的工具,他与容器联系紧密,每一种容器的空间分配都是通过空间分配器alloctor实现的.理解alloctor的实现原理,对内存结构以及数据存储形式会有更清晰直观的认识.
1.两种C++类对象实例化方式的异同
在c++中,创建类对象一般分为两种方式:一种是直接利用构造函数,直接构造类对象,如 Test test();另一种是通过new来实例化一个类对象,如 Test *pTest = new Test;那么,这两种方式有什么异同点呢?
我们知道,内存分配主要有三种方式:
(1)静态存储区分配:内存在程序编译的时候已经分配好,这块内存在程序的整个运行空间内都存在.如全局变量,静态变量等.
(2)栈空间分配:程序在运行期间,函数内的局部变量通过栈空间来分配存储(函数调用栈),当函数执行完毕返回时,相对应的栈空间被立即回收. 主要是局部变量.
(3)堆空间分配:程序在运行期间,通过在堆空间上为数据分配存储空间,通过malloc和new创建的对象都是从堆空间分配内存,这类空间需要程序员自己来管理,必须通过free()或者是delete()函数对堆空间进行释放,否则会造成内存溢出.
那么,从内存空间分配的角度来这两种方式的区别,就比较容易区分:
对于第一种方式来说,是直接通过调用Test类的构造函数来实例化Test类对象的,如果该实例化对象是一个局部变量,则其是在栈空间分配相应的存储空间.
对于第二种方式来说,就显得比较复杂.这里主要以new类对象来说明一下.new一个类对象,其实是执行了两步操作:首先,调用new在堆空间分配内存,然后调用类的构造函数构造对象的内容;同样,使用delete释放时,也是经历了两个步骤:首先调用类的析构函数释放类对象,然后调用delete释放堆空间.
2.C++ STL空间配置器实现
很容易想象,为了实现空间配置器,完全可以利用new和delete函数并对其进行封装实现STL的空间配置器,的确可以这样.但是,为了最大化提升效率,SGI STL版本并没有简单的这样做,而是采取了一定的措施,实现了更加高效复杂的空间分配策略.由于以上的构造都分为两部分,所以,在SGI STL中,将对象的构造切分开来,分成空间配置和对象构造两部分.
内存配置操作:alloc::allocate()实现
内存释放操作:alloc::deallocate()实现
对象构造操作: ::construct()实现
对象释放操作: ::destroy()实现
STL对象构造与释放结构图如下所示:

关于对象的构造和释放的实现,此处buxijia不细讲,但其中利用了replacement new技术,单独说一下.
replacement new技术实际上就是将一个对象构造在指定的内存区域中.该内存区域可以是静态数据区,栈空间或者是堆空间,对于内存的管理方式不变.如下代码说明replacement new的用法.
#include<new.h> Class Test {...}; char *p = (char *)malloc(sizeof(Test)); Test *tp = new(p) Test();//replacement new
关于内存空间的配置与释放,SGI STL采用了两级配置器:一级配置器主要是考虑大块内存空间,利用malloc和free实现;二级配置器主要是考虑小块内存空间而设计的(为了最大化解决内存碎片问题,进而提升效率),采用链表free_list来维护内存池(memory pool),free_list通过union结构实现,空闲的内存块互相挂接在一块,内存块一旦被使用,则被从链表中剔除,易于维护.
free_list的结构如下所示:
union obj{ union obj *free_list_link; char client_data[1]; };
free_list的实现技巧如下图所示:

从free_list取出内存块示意图:

释放内存块加入free_list示意图:

以上内容仅供参考学习,欢迎大家交流讨论.转载请注明出处.
参考资料
[1] https://www.cnblogs.com/tony-li/p/4111588.html
[2]STL源码剖析
C++ STL学习之 空间配置器(allocator)的更多相关文章
- C++ 空间配置器(allocator)
C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...
- STL学习笔记:空间配置器allocator
allocator必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::referenc ...
- STL源码剖析——空间配置器Allocator#1 构造与析构
以STL的运用角度而言,空间配置器是最不需要介绍的东西,因为它扮演的是幕后的角色,隐藏在一切容器的背后默默工作.但以STL的实现角度而言,最应该首先介绍的就是空间配置器,因为这是这是容器展开一切运作的 ...
- 《STL源码剖析》chapter2空间配置器allocator
为什么不说allocator是内存配置器而说是空间配置器,因为空间不一定是内存,也可以是磁盘或其他辅助介质.是的,你可以写一个allocator,直接向硬盘取空间.sgi stl提供的配置器,配置的对 ...
- STL源码剖析 — 空间配置器(allocator)
前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...
- STL源码剖析——空间配置器Allocator#2 一/二级空间配置器
上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator del ...
- STL之空间配置器allocator
摘要 C++STL的空间配置器将内存的分配.释放,对象的构造.析构都分开执行,内存分配由alloc::allocate()负责,内存的释放由alloc::deallocate()负责:对象的构造由:: ...
- STL源码剖析——空间配置器Allocator#3 自由链表与内存池
上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...
- STL——模拟实现空间配置器
目录 问题 SGI版本空间配置器-std::alloc 一级空间配置器 二级空间配置器 Refill.chunkAlloc函数 最后,配置器封装的simple_alloc接口 问题 我们在日常编写C+ ...
随机推荐
- TF-tf.arg_max 介绍
定义为 def arg_max(input, dimension, name=None) 作用是取行或者列的最大值的位置. input:类型为 float32, float64, int64, int ...
- liunx redis集群添加密码
第一种方法: 修改每个节点redis.conf配置文件: masterauth 123456 requirepass 123456 各个节点的密码都必须一致,否则Redirected就会失败 重新启动 ...
- background-image属性
background-image 属性 实例,设置body元素的背景图像: body { background-image: url('paper.gif'); background-color: # ...
- 【由浅入深理解java集合】(四)——集合 Queue
今天我们来介绍下集合Queue中的几个重要的实现类.关于集合Queue中的内容就比较少了.主要是针对队列这种数据结构的使用来介绍Queue中的实现类. Queue用于模拟队列这种数据结构,队列通常是指 ...
- 【python】实用的logging封装
#!/usr/bin/python import logging import logging.handlers def set_logger(filename, logmod): log_size ...
- excel导出导入通用方法
/** * 方法说明:批量导出通用方法 * 创建时间:2018年8月24日 *** * @param filePath 文件地址 * @param sheetName 分页名称 * @param ti ...
- log4net可视化查询
转自:https://www.cnblogs.com/huangxincheng/p/9120028.html 小步快跑的公司可以最简化操作直接通过log4net将日志写入ElasticSearch ...
- 《C和指针》---指针
内存和地址 计算机的内存由许多的位(bit)组成,每个位可以容纳值0或1. 由于一个位所能表示的范围太有限,所以通常许多位合成一组作为一个单元. 这些位置的每一个都被称为字节(byte),每个字节包含 ...
- nohup & 及端口查看
ps -aux | grep processName | grep -v grep | awk '{print $2}' a:显示所有程序 u:以用户为主的格式来显示 x:显示所有程序,不以终端机来区 ...
- 函数防抖 & 函数节流
避免一个函数频繁执行 - 避免程序卡顿 js 是单线程的,setTimeout 这样的函数是异步的 异步的代码,交给对应的模块进行处理 模块在会将异步任务,在主线程执行完所有同步代码后,加入事件队列 ...