内存的分配需要解决的几个问题:

1. 向系统的heap空间请求空间;

2. 考虑多线程的状态问题;

3. 考虑内存空间不足时的应对策略;

4. 考虑过多“小内存块”的碎片问题。

SGI的STL底层使用malloc()和free()完成,分为两层内存分配配置器:

第一级主要处理相对内存大小较大的分配请求size>128B,第二级主要处理内存请求相对较小的分配请求。

第一级直接使用malloc和free函数分配内存,并配有类似C++的set_new_handler()来处理内存分配不足的特殊处理。

例如:

static void* allocate(size_t n)

{

  void * result = malloc(n);

  if (0 == result)

    result = oom_malloc(n); // 内存不足时的处理函数

  return result;

}

// 内存不足时的处理函数片段

{

  for(;;)

  {

    my_malloc_handler = __malloc_alloc_oom_handler;

    if (0 == my_malloc_handler) {__THROW_BAD_ALLOC;}

    (*my_molloc_handler)(); // 尝试释放内存操作

    result = malloc(n); // 再次尝试分配内存

    if (result) return result;

  }

}

SGI是用malloc而不是::operator new分配内存,主要可能是由于历史因素,另外,new没有realloc的功能;SGI不能使用C++的set_new_handler(),也是因为他没有使用::operator new,因此需要定义一个类似的功能,如上。

第二级维护16个内存自由链表(free_list),size从8B,16B,24B,...,128B的16个链表free_list,当用户请求内存时,从合适的链表给出内存,以解决小内存块产生的碎片,以防浪费。

free_list节点结构:

union obj

{

  union obj * free_list_link;

  char data[1]; // 实际内存

};  // 使用union定义节点,不至于像struct那样浪费一个指针的空间

内存池:

每个free_list维护一个链表,当链表空间不足时需要向内存池申请,如果内存池有内存,则尽可能的给出内存量给free_list[i],如果内存池已经空了,只能从系统的heap空间申请内存,此时申请的内存量一般为需求量的2倍+随配置次数增大的附加量。

如:free_list[5]没有内存了,需要从内存池中申请,此时内存池如果有标准量(如20),则给出20块;如果不够,则都给出,并返回给出的块数;然后1块交出,其余放入free_list[5]中链表维护.

如:free_list[9]没有内存了,从内存池申请时,内存池也没有了,则内存池向系统申请内存,大小为配置的两倍+x,成功则按上述方法分配;如果失败,则转由第一级配置器处理(可以处理内存不足时策略,如释放内存等)。

SGI的uninitialized_copy和uninitialized_fill:

在容器的构造中,分成两步:1. 分配足够大的内存空间; 2. 在每个位置上进行构造函数.

uninitialized_copy和uninitialized_fill就是第二个步骤做的事情,将对应位置的内存进行构造,copy构造或用某个x构造。并且他们具有“commit or rollback”语义,即要么全初始化成功,要么就全初始化失败。

STL源码--Allocator学习的更多相关文章

  1. c++ stl源码剖析学习笔记(一)uninitialized_copy()函数

    template <class InputIterator, class ForwardIterator>inline ForwardIterator uninitialized_copy ...

  2. STL源码剖析 学习笔记 MiniSTL

    https://github.com/joeyleeeeeee97 目录: 第二章 空间适配器 第三章 迭代器 第四章 序列式容器(vector,list,deque,stack,heap,prior ...

  3. c++ stl源码剖析学习笔记(二)iterator

    ITERATOR 迭代器 template<class InputIterator,class T> InputIterator find(InputIterator first,Inpu ...

  4. c++ stl源码剖析学习笔记(三)容器 vector

    stl中容器有很多种 最简单的应该算是vector 一个空间连续的数组 他的构造函数有多个 以其中 template<typename T> vector(size_type n,cons ...

  5. STL源码剖析-学习笔记

    1.模板是一个公式或是蓝图,本身不是类或是函数,需进行实例化的过程.这个过程是在编译期完成的,编译器根据传递的实参,推断出形参的类型,从而实例化相应的函数 2. 后续补充-.

  6. 侯捷STL课程及源码剖析学习2: allocator

    以STL 的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体地说是指容器,container)的背后,默默工作默默付出. 一.分配器测试 测试代码 #include < ...

  7. 侯捷STL课程及源码剖析学习1

    1.C++标准库和STL C++标准库以header files形式呈现: C++标准库的header files不带后缀名(.h),例如#include <vector> 新式C hea ...

  8. stl源码学习(版本2.91)--list

    stl源码学习(版本2.91)--list 一,阅读list()构造函数的收获 1,默认构造函数的作用和被调用的时机 struct no{ no(int i){} //no(){ // std::co ...

  9. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

随机推荐

  1. 关于javascript tween的学后小感想

    今天决定了解一下tween算法,首先得下载个tween.js看看吧,好吧,有点被惊艳到了. 也让我想起了之前上数学课时,听到过的一句话:“数学世界是神秘.纯洁.有魅力的”,一直 记得这句话,期待有朝一 ...

  2. zk抢主

    package com.autonavi.tinfo.t1.traffic.pub.openlr.util; import java.util.Collections;import java.util ...

  3. mvc之页面强类型

    为什么使用页面强类型: 一个页面只能定义 为一个强类型.因为 我们自己写@Html.TextBox("Qq"); 有可能写错,所以我们就在 编译阶段就把页当作一个类型然后使用lam ...

  4. 简单来谈谈alloc分配器

    之前说道alloc是原G2.9版本的默认的分配器,这篇就把alloc的原理梳理梳理,顺便简单介绍下有关的内存管理. 一般而言,我们通常习惯的内存分配操作和释放操作是这样的: class Foo {…} ...

  5. mysql之触发器入门

    触发器语法: CREATE TRIGGER <触发器名称>  --触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.{ BEFORE |  ...

  6. vue-cli#2.0 webpack 配置分析

    目录结构: ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-s ...

  7. Hibernate对象的状态

    站在持久化的角度, Hibernate 把对象分为 4 种状态: 1. 持久化状态 2. 临时状态 3. 游离状态 4. 删除状态 Session 的特定方法能使对象从一个状态转换到另一个状态. 下面 ...

  8. XproerIM-V1,2,12,65475发布。

    下载地址:http://yunpan.cn/QTCxKvcpC4Iet  访问密码 9141更新记录:1.登陆面板增加帐号列表功能.

  9. Add Binary <leetcode>

    Given two binary strings, return their sum (also a binary string). For example,a = "11"b = ...

  10. SQL常用代码收集

    1.存储过程中,使用in查询时的参数处理方式 使用情形描述:传入存储过程的参数为一个字符串@IDs,以固定分隔符连接 新建字符串分割函数,然后将分割结果传入存储过程: CREATE FUNCTION ...