C++ STL学习之 空间配置器(allocator)

标签(空格分隔): C++ STL


众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在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源码剖析

原文地址:https://www.cnblogs.com/nolan24/p/9781017.html

时间: 2024-08-03 08:58:26

C++ STL学习之 空间配置器(allocator)的相关文章

2.SGI STL第二级空间配置器__default_alloc_template的chunk_alloc函数

SGISTL默认使用二级空间配置器,当需要配置的区块大于128 bytes时SGI STL调用一级空间配置器,一级空间配置器的allocate函数直接使用malloc分配内存,deallocate函数直接使用free释放内存.当需要配置的区块小于128 bytes时SGI STL调用二级空间配置器. 相比于一级空间配置器简单粗暴的内存使用方法,二级空间配置器对内存的使用显得精细很多. 二级空间配置器的具体用法请看书,我就不抄书了,只对二级空间配置器中容易糊涂的地方写一下我的理解. 内存池和fre

STL学习笔记--2、空间配置器 allocator

2.1标准接口 allocator::value_type allocator::pointer allocator::const_pointer allocator::reference allocator::const_reference allocator::size_type allocator::difference_type allocator::rebind allocator::allocator()//默认构造函数 allocator::allocator(const allo

STL源码剖析 — 空间配置器(allocator)

前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配置器,配置的对象,是内存.(以下内容来自<STL源码剖析>) 空间配置器的标准接口 根据STL的规范,allocator的必要接口 各种typedef 1 allocator::value_type 2 allocator::pointer 3 allocator::const_pointer 4

STL源码剖析——空间配置器Allocator#2 一/二级空间配置器

上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator delete().这两个全局函数相当于C的malloc() 和free() 函数.而SGI正是以malloc() 和free() 完成内存的配置与释放. 考虑到小型区块可能造成的内存破碎问题,SGI设计了两级的空间配置器.第一级直接使用malloc() 和free() ,而第二级则视情况采用不同的策略:当

STL源码剖析——空间配置器Allocator#3 自由链表与内存池

上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refill()函数——重新填充自由链表 前情提要,从上节第二级配置器的源码中可以看到,在空间配置函数allocate()中,当所需的某号自由链表为空时,才会调用refill()函数来填充链表.refill()函数默认申请20块区块的内存(5行),但所得内存不一定就是20块,要看当前内存池的剩余情况和堆容量的

STL:二级空间配置器浅谈

我们在编写程序过程中,需要内存时,我们第一反应就是malloc,但是这样容易产生内片无法被利用. 在STL中提到了空间适配器,它主要分为两级:一级空间适配置器,二级空间配置器.一级空间适配器是对malloc的简单包装,它内部的allocate()和reallocate()都是在调用malloc()和realloc()不成功后,再调用oom_malloc()和oom_realloc()[清理内存],重复多次后,如果还不成功便调用_THROW_BAD_ALLOC,丢出bad_alloc异常信息. 二

stl源码剖析 详细学习笔记 空间配置器

//---------------------------15/04/05---------------------------- /* 空间配置器概述: 1:new操作包含两个阶段操作 1>调用::operator new配置内存(底层使用malloc来申请内存). 2>调用函数的构造函数,构造对象内容. delte和new一样,先调用析构函数,再调用::operator delete释放内存. 2:为了效率,stl把两个阶段分开来. 1>内存配置操作: alloc::allocate

SGI STL第二级空间配置器空间释放函数deallocate

union obj{ obj * free_list_link ; char client_data[1] ; }; __default_alloc_template拥有配置器标准接口函数deallocate().该函数首先判断区块大小,大于128bytes就调用第一级配置器,小于128bytes就找出相应的free list将区块回收: <span style="font-size:18px;">//p is not 0/null static void dealloca

[C++] 空间配置器——allocator类

1.new和delete有一些灵活性上的局限:new把内存分配和对象构造组合在了一起:delete将对象析构和内存释放组合在了一起. 2.当分配一大块内存时,我们通常计划在这块内存上按需构造对象,在此情况下,我们希望将内存分配和对象构造分离:这意味着我们可以分配大块内存,但只在真正需要的时候才真正执行对象创建操作. 3.allocator类,定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来,它提供一种类型感知的内存分配方法,它分配的内存是原始的.未构造的.在分配内存时,它会根据