正在学习中,如果有错,还请多多指教,根据不断的理解,会进行更改,更改之前的样子都会保留下来,记录错误是最大的进步,嗯嗯!

具有次配置力的SGI空间配置器(SGI是STL的一种版本,也有其他的版本)

这里我就不贴出来具体成员和接口的实现了,网上可以搜到STL的源码

C++中,new一个变量可以分为两个阶段,1.分配空间 2.调用构造函数;delete变量也分为两个步骤,1.调用析构函数 2.释放空间

SGI的alloc将这两部分分开,让空间的分配释放和构造析构由不同的函数调用,区分他们的操作

空间的分配和释放由alloc::alloclate()  alloc::dealloclate()实现 构造和析构由alloc::construct() alloc::destory()函数负责,他们在头文件

#include<stl_alloc.h> //负责内存空间的配置和释放 #include<stl_construct.h> //负责对象内容的构造和析构 这两个头文件都包含在#include<memory>当中

先讲一下析构和构造的大概思路  

    • 这里提到一个概念_type_traits<T>(这是个模板),首先通过value_type()获得迭代器所指向对象的类型然后使用_type_traits进行类型判别,该对象是否是trivial(无关痛痒的) destructor,我对这里的理解是,当迭代器所指对象的类型为POD(Plain Old Data)类型(PS:POD类型可以理解为传统的C语言类型,就是int那一类的)是不需要专门调用析构函数的,等待系统自动释放int所占用的空间即可,但当迭代器所指对象的类型为string对象(或者是其他你自己写的类的对象),就不能依靠系统,需要调用专门的析构函数挨个析构。进行类型判别之后,就可以提高工作效率。(destory()对char*等类型也有相应的特化)
    • 构造函数就采用泛式构造,使用new进行构造
  • 下面讲一下我对空间的配置与释放的理解
    • C++对内存配置的基本操作依靠::operator new()和::operator delete()这两个全局函数,这两个函数只起到分配和释放内存的作用,并不会调用构造函数和析构函数,他们就相当于C语言中的malloc()和free()函数,SGI正是以malloc()和free()进行空间的管理
    • 为了解决内存碎片的问题(当不断地malloc空间时候,找到足够大小的空间就拿来用,不可避免的的会产生内存碎片),于是就有了内存池的概念(内存池就是系统实现给开辟出一大块空间等待使用,当需要空间的时候直接从内存池中取,当内存池中的内存也不够使用时,再去Heap中开辟新的空间注入到内存池当中)

下面就比较重要了,SGI空间配置器采用了两级配置器,分为第一级配置器和第二级配置器,第一级配置器就是拿malloc()实现的,第二级配置器采用了内存池的概念;

先来讲第一级配置器,第一级配置器的实现就是用的malloc()(因为很重要所以多说几遍),它会不断地尝试开辟内存,如果没有内存可供开辟,就会尝试释放空间,然后再取尝试开辟空间,第一级配置器比较重要的一点就是实现了类似C++中new-handler机制,用来处理内存不足的情况

内存池是使用链表结构实现的(个人感觉和哈希桶的方法类似),而不采用顺序表,这样就可以更好的解决内存碎片的问题了。

注意,这里的freelists是链表!

注意!这里之前写的不太清楚,freelists是一个顺序表,每一个单元下边都连接这一个链表,当区块被客端(client)使用就会像上图一样将区块拨出去,然后改变指针指向下一个节点(就是采用头删)

每个链表节点所管理的区块大小也是不一样的,第一个节点管理8bytes,第二个16bytes。。。以此类推,最后一个节点管理128bytes,所以当超过128字节第二级配置器无法处理,就只好调用第一级配置器(内存不足时也会调用第一级配置器,因为第一级配置器里面有内存不足处理例程)

下面给出链表节点的实现

 union obj
{
union obj *free_list_link;
char client_data[];//The client sees this;
};

里面的联合体指针就是指向下一个节点的指针,那个char是指向实际内存块的指针,采用联合体可以减少内存的消耗,不必专门维护一个指向下一个节点的指针

当节点所指的内存块是空闲块时,obj被看做一个指针,指向下一个节点,当节点已经被分配了内存之后,被视为一个指针,指向实际区块

当分配函数allocate()(alloc中申请内存的函数)发现没有可用的区块之后,就会去内存池中申请新的区块(调用chunk_alloc()函数) ,默认申请20个区块,当内存池的可用内存不足20个区块,有多少给多少,如果连一个区块的内存都不够,就往内存池中注入内存(就是再去开辟一些放进内存池里),就会去free_lists中遍历,寻找内存池分配给自由链表但是却处于空闲状态的节点,将这些节点的存储空间归还个内存池,再递归去使用chunk_alloc()函数判断是否空间够分配;如果很不幸,还是不够用,那么注意!!会将内存池中剩余的小空间分配成低位区块分给自由链表(就是说假如需要申请16个字节的节点区块,不够了,但是内存池中有8个字节的空间,当然不能够浪费咯,赶紧分配出去)然后去往内存池中注入内存(就是再去开辟一些放进内存池里)。

这个是《STL源码剖析》里的一个例子

当整个系统堆得内存都不够了的时候,就chunk_malloc()就会四处寻找可用内存,尝试释放一些没用的空间,如果还是无法找到就去调用第一级配置器,因为一级配置器里有内存不足处理例程

STL库的内存配置器(allocator)的更多相关文章

  1. 自己动手实现STL 01:内存配置器的实现(stl_alloc.h)

    一.前言 在STL中,容器是其中的重中之重,基本的STL中的算法,仿函数等都是围绕着容器实现的功能.而,内存配置器,是容器的实现的基础.所以,我第一次要去编写便是内存配置器的实现.在STL中,内存配置 ...

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

    众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间 ...

  3. 《STL源码剖析》chapter2空间配置器allocator

    为什么不说allocator是内存配置器而说是空间配置器,因为空间不一定是内存,也可以是磁盘或其他辅助介质.是的,你可以写一个allocator,直接向硬盘取空间.sgi stl提供的配置器,配置的对 ...

  4. SGI STL内存配置器存在内存泄漏吗?

    阅读了SGI的源码后对STL很是膜拜,很高质量的源码,从中学到了很多.温故而知新!下文中所有STL如无特殊说明均指SGI版本实现. STL 内存配置器 STL对内存管理最核心部分我觉得是其将C++对象 ...

  5. STL内存配置器

    一.STL内存配置器的总体设计结构 1.两级内存配置器:SGI-STL中设计了两级的内存配置器,主要用于不同大小的内存分配需求,当需要分配的内存大小大于128bytes时, 使用第一级配置器,否则使用 ...

  6. STL之空间配置器allocator

    摘要 C++STL的空间配置器将内存的分配.释放,对象的构造.析构都分开执行,内存分配由alloc::allocate()负责,内存的释放由alloc::deallocate()负责:对象的构造由:: ...

  7. STL——模拟实现空间配置器

    目录 问题 SGI版本空间配置器-std::alloc 一级空间配置器 二级空间配置器 Refill.chunkAlloc函数 最后,配置器封装的simple_alloc接口 问题 我们在日常编写C+ ...

  8. STL-空间配置器(allocator)

    STL的空间配置器作为STL六大部件的重要组成部分,它总是隐藏在一切组件的背后.它主要负责动态空间的分配.释放等管理工作.整个STL的操作对象(所有的数值)都存放在容器之内,而容器一定需要配置空间以置 ...

  9. C++ 空间配置器(allocator)

    C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...

随机推荐

  1. Tomcat的SSL证书配置以及Tomcat+Nginx实现SSL配置

    把jks上传到java容器在的服务器上,路径只要不是webapps下就可以,然后到conf目录下server.xml里配置 <Connector port=" protocol=&qu ...

  2. WCF启用日志追踪

    调用使用http post调用WCF Restful服务时,WCF会自动反序列化body里的实体,如果实体反序列化不成功时,会返回一个请求错误,让去看服务器日志.需要启用日志追踪功能,才能看到具体的情 ...

  3. 9.7 js进阶总结2

    数组元素添加 将一个或多个新元素添加到数组结尾,并返回数组新长度 var week_len = week.push(‘星期四’,‘星期五’); 将一个或多个新元素添加到数组开始,数组中的元素自动后移, ...

  4. Redis学习手册——转载

    转载出处:http://www.cnblogs.com/stephen-liu74/archive/2012/04/16/2370212.html 为什么自己当初要选择Redis作为数据存储解决方案中 ...

  5. truncate和delete之间有什么区别

    TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行.但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源 ...

  6. yum -y upgrade 和 yum -y update 区别

    分别测试yum -y upgrade和yum -y update 升级前 系统版本: CentOS5.5 内核版本: 2.6.18-194.el5 升级前做过简单配置文件修改 yum -y upgra ...

  7. Java中前台JSP请求Servlet实例(http+Servlet)

    1.前台jsp代码 himily.jsp,定义了用户名和密码两个输入框,使用post方式提交:/order-web/HimilyServlet其中order-web为站点名称,HimilyServle ...

  8. linux whoami命令

    whoami显示的是当前"操作用户"的用户名.

  9. php 快速排序

    快速排序是以其中一个数为比较标准,其他比较的数分块处理,应用递归按相同想法处理数据 比如:4 3 6 2 1 7 8 以4为比较对象 排序为 3 2 1 6 7 8 左边为 3 2 1 右边 为 6 ...

  10. 获取android控件的高度

    问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没有简单 ...