空间配置器

标准的空间配置器:allocator

SGI也定义有一个符合部分标准,名为allocator的配置器,但是从未使用过它,也不建议使用,原因是效率不佳,只是对new,delete的一层简单包装。

特殊的空间配置器:alloc

先考虑一般而言,我们习惯的C++申请内存和释放内存的流程,

class Foo{ ... };
Foo* pf = new Foo;
delete pf;

new包含了两部分操作:申请空间,构造对象内容,delete也包含了两部分操作:析构,释放内存。

为了精密分工,allocator决定将这两阶段区分开来,

  • 内存配置操作由alloc:allocate负责,内存释放操作由alloc:deallocate负责,
  • 对象构造由::construct负责,对象析构由::destroy负责。

这两部分内容被定义在 < memory >中,其中包含的两个头文件,stl_alloc.h和stl_construct.h有上述内容。从属关系如下所示:
在这里插入图片描述

对象构造和析构行为

construct()接收一个指针p和一个初值value,作用是把初值设定到指针所指的空间上。
destroy()有两个版本,一种支持指针(指定析构),一种支持迭代器(范围析构)。

空间配置和释放行为

设计哲学:

  • 向system heap要求空间
  • 考虑多线程情况
  • 考虑内存不足的应变措施
  • 考虑过多“小型区块”可能造成的内存碎片问题

针对上述设计哲学,

  • 空间上,SGI采用的是malloc和free来完成内存的配置和释放
  • 内存碎片上,采用的是双级配置器

对于双级配置器的表述,

  • 第一级直接使用malloc和free (其实加装了一层外壳,使其符合规格)
  • 第二级视情况采取不同策略:
    • 配置区块超过128bytes,视为足够大,用一级
    • 配置区块小于128bytes,视之过小,用memory pool整理方式(二级)

一二级配置器的关系图示如下:
在这里插入图片描述
针对上图中的new handler机制,是在内存配置需求无法满足时可以调用一个你指定的函数(在调用bad alloc之前)。

配置器

一级配置器剖析:

为什么不使用new?

  • 可能是历史因素
  • c++未提供realloc的内存配置操作,导致不能直接使用set_new_handler,需要仿真一个。
二级配置器剖析:

前面提到了二级配置器是为了防止内存碎片问题,不仅是碎片问题,配置时的额外负担也是问题(系统在管理空间是需要缓存空间来记录内存大小)。二级配置器的做法是:

  • 足够大就交给一级
  • 小于128bytes用内存池管理(次级配置)

次级配置器的具体做法:

  • 每次配置一大块内存,并维护对应的自由链表,下次再有相同大小需求直接从链表中拨出
  • 如果是释还空间,就由配置器回收到自由链表中
  • 为了方便管理,任何小额区块的内存需求量上调至8的倍数,维护的是16个自由链表,8-128
配置器与函数的对应及逻辑:

申请过程allocate

  • 判断区块大小决定调用几级配置器。
  • 在二级中如果有可用就直接拨出,没有就将区块大小上调至8的倍数边界进行refill

释放过程deallocate

  • 判断区块大小决定调用几级配置器。
  • 大于128一级回收,小于二级找对应的free list回收

重新填充过程refill

  • free list没有可用时调用,去内存池取,缺省取20个,内存池不够就小于20
  • 大于128一级回收,小于二级找对应的free list回收

内存池申请过程chunk_alloc

  • 水量充足取20,不足少于20
  • 连一个区块空间都不够就去malloc,新水量为需求量的两倍,再加上一个随配置次数增加的附加量
  • 如果system heap空间也不够了,就去free list四处寻找并挖出,再找不到就去一级配置器
  • 或许一级配置器有机会,计算没有机会还可以调用out-of-memory处理机制

内存池的实际操作过程如下所示:
在这里插入图片描述

内存基本处理工具

STL定义了五个全局函数,作用于未初始化空间上,分别是construct(),destroy(),uninitialized_copy(),uninitialized_fill()和uninitialized_filln()。这部分没看太明白,整理的比较简略。

uninitialized_copy()

将内存的配置和对象的构造行为分离,目前能记住的致使这个函数对实现一个容器有帮助,因为容器的全区间构造函数通常需要下述两个步骤完成:

  • 配置内存区块,足以包含范围内的所有元素
  • 使用该函数在该内存区块上构造元素
uninitialized_fill()

也能将内存的配置和对象的构造行为分离,

uninitialized_filln()

也能将内存的配置和对象的构造行为分离,会为指定范围内的所有元素设定相同的初值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值