STL源码剖析---空间配置器

STL源码剖析——空间配置器 前言 空间配置是为存储数据 阅读详情
看过STL空间配置器的源码,总结一下:
      1、STL空间配置器:主要分三个文件实现,stl_construct.h  这里定义了全局函数construct()和destroy(),负责对象的构造和析构。stl_alloc.h文件中定义了一、二两级配置器,彼此合作,配置器名为alloc. stl_uninitialized.h 这里定义了一些全局函数,用来填充(fill)或复制(copy)大块内存数据,他们也都隶属于STL标准规划。
      在stl_alloc.h中定义了两级配置器,主要思想是申请大块内存池,小块内存直接从内存池中申请,当不够用时再申请新的内存池,还有就是大块内存直接申请。当申请空间大于128字节时调用第一级配置器,第一级配置器没有用operator::new和operator::delete来申请空间,而是直接调用malloc/free和realloc,并且实现了类似c++中new-handler的机制。所谓c++ new handler机制是,你可以要求系统在内存配置需求无法被满足时,调用一个指定的函数。换句话说,一旦::operator::new无法完成任务,在丢出std::bad_alloc异常状态之前,会先调用由客端指定的处理例程,该处理例程通常称为new-handler.new-handler解决内存做法有特定的模式。SGI第一级配置器的allocate()和realloc都是在调用malloc和realloc不成功后,改调用oom_malloc()和oom_realloc(),后两者都有内循环,不断调用"内存不足处理例程",期望在某次调用之后,获得足够的内存而圆满完成任务。但如果“内存不足处理例程“并未被客端设定,oom_malloc()和oom_realloc便调用_THROW_BAD_ALLOC, 丢出bad_alloc异常信息,或利用exit(1)硬生生中止程序。
     在stl_alloc.h中定义的第二级配置器中,如果区块够大,超过128字节时,就移交给第一级配置器处理。当区块小于128字节时,则以内存池管理,此法又称为次层配置,每次配置一大块内存,并维护对应的自由链表(free-list)。下次若再有相同大小的内存需求,就直接从free-list中拔出。如果客端释还小额区块,就由配置器回收到free-lists中,另外,配置器除了负责配置,也负责回收。为了管理方便,SGI第二级配置器会主动将任何小额区块的内存需求量上调至8的倍数。并维护16个free-lists,各自管理大小分别为8,16,24,32,40,48,56,64,72,80,88,96,104, 112,120,128 字节的小额区块。当申请小于等于128字节时就会检查对应的free list,如果free-list中有可用的区块,就直接拿来,如果没有,就准备为对应的free-list 重新填充空间。新的空间将取自内存池,缺省取得20个新节点,如果内存池不足(还足以一个以上的节点),就返回的相应的节点数.如果当内存池中连一个节点大小都不够时,就申请新的内存池,大小为2*total_bytes+ROUND_UP(heap_size>>4),totoal_bytes 为申请的空间大小,ROUND_UP调整为8的倍数,heap_size为当前总申请内存池的大小。如果申请该内存池成功就把原来内存池中剩下的空间分配给适当的free-list.万一山穷水尽,整个system heap空间都不够了(以至无法为内存池注入源头活水),malloc()行动失败,就会四处寻找有无"尚有未用区块,且区块足够大 "之free lists.找到了就挖一块交出,找不到就调用第一级配置器。第一级配置器其实也是使用malloc来配置内存。但它有out-of-memory处理机制(类似new-handler机制),或许有机会释放其他的内存拿来此处使用。如果可以就成功,否则发出bad_alloc异常。
      2、STL的默认内存分配器
      隐藏在这些容器后的内存管理工作是通过STL提供的一个默认的allocator实现的。当然,用户也可以定制自己的allocator,只要实现allocator模板所定义的接口方法即可,然后通过将自定义的allocator作为模板参数传递给STL容器,创建一个使用自定义allocator的STL容器对象,如:
    stl::vector<int, UserDefinedAllocator> array;
      大多数情况下,STL默认的allocator就已经足够了。这个allocator是一个由两级分配器构成的内存管理器,当申请的内存大小大于128byte时,就启动第一级分配器通过malloc直接向系统的堆空间分配,如果申请的内存大小小于128byte时,就启动第二级分配器,从一个预先分配好的内存池中取一块内存交付给用户,这个内存池由16个不同大小(8的倍数,8~128byte)的空闲列表组成,allocator会根据申请内存的大小(将这个大小round up成8的倍数)从对应的空闲块列表取表头块给用户。
这种做法有两个优点:
     (1)小对象的快速分配。小对象是从内存池分配的,这个内存池是系统调用一次malloc分配一块足够大的区域给程序备用,当内存池耗尽时再向系统申请一块新的区域,整个过程类似于批发和零售,起先是由allocator向总经商批发一定量的货物,然后零售给用户,与每次都总经商要一个货物再零售给用户的过程相比,显然是快捷了。当然,这里的一个问题时,内存池会带来一些内存的浪费,比如当只需分配一个小对象时,为了这个小对象可能要申请一大块的内存池,但这个浪费还是值得的,况且这种情况在实际应用中也并不多见。
     (2)避免了内存碎片的生成。程序中的小对象的分配极易造成内存碎片,给操作系统的内存管理带来了很大压力,系统中碎片的增多不但会影响内存分配的速度,而且会极大地降低内存的利用率。以内存池组织小对象的内存,从系统的角度看,只是一大块内存池,看不到小对象内存的分配和释放。
实现时,allocator需要维护一个存储16个空闲块列表表头的数组free_list,数组元素i是一个指向块大小为8*(i+1)字节的空闲块列表的表头,一个指向内存池起始地址的指针start_free和一个指向结束地址的指针end_free。空闲块列表节点的结构如下:
union obj
{
	union obj * free_list_link;
	char client_data[1];
};
      这个结构可以看做是从一个内存块中抠出4个字节大小来,当这个内存块空闲时,它存储了下个空闲块,当这个内存块交付给用户时,它存储的时用户的数据。因此,allocator中的空闲块链表可以表示成:
    obj* free_list[16];
      3、分配算法

// 算法:allocate
// 输入:申请内存的大小size
// 输出:若分配成功,则返回一个内存的地址,否则返回NULL
{
	if(size 大于 128)
		启动第一级分配器直接调用malloc分配所需的内存并返回内存地址;
	else
	{
		将size向上round up成8的倍数并根据大小从free_list中取对应的表头free_list_head
		if(free_list_head 不为空)
		{
			从该列表中取下第一个空闲块并调整free_list,返回free_list_head
		}
		else
		{
			调用refill算法建立空闲块列表并返回所需的内存地址
		}
	}
}


// 算法:refill
// 输入:内存块的大小size
// 输出:建立空闲块链表并返回第一个可用的内存地址
{
	调用chunk_alloc算法分配若干个大小为size的连续内存区域并返回起始地址chunk和成功分配的块数nobj
	if(块数为1)
		直接返回 chunk;
	else
	{
		开始在chunk地址块中建立free_list
		根据size取free_list中对应的表头元素free_list_head 
		将free_list_head 指向chunk中偏移起始地址为size的地址处,即free_list_head = (obj*)(chunk+size)
		再将整个chunk中剩下的nobj-1个内存块串联起来构成一个空闲列表
		返回chunk,即chunk中第一个空闲的内存块
	}
}


// 算法:chunk_alloc
// 输入:内存块的大小size,预分配的内存块数nobj(以引用传递)
// 输出:一块连续的内存区域的地址和该区域内可以容纳的内存块的块数
{
	计算总共所需的内存大小total_bytes
	if(内存池足以分配,即end_free-start_free >= total_bytes)
	{
		则更新start_free
		返回旧的start_free
	}
	else if(内存池不够分配nobj个内存块,但至少可以分配一个)
	{
		计算可以分配的内存块数并修改nobj
		更新start_free并返回原来的start_free
	}
	else     // 内存池连一个内存块都分配不了
	{
		先将内存池的内存块链入到对应的free_list中后
		调用malloc操作重新分配内存池,大小为2倍的total_bytes为附加量,start_free指向返回的内存地址
		if(分配不成功)
		{
			if(16个空闲列表中尚有空闲块)
				尝试将16个空闲列表中空闲块回收到内存池中再调用chunk_alloc(size,nobj)
			else
				调用第一级分配器尝试out of memory机制是否还有用
		}
		更新end_free为start_free+total_bytes,heap_size为2倍的total_bytes
		调用chunk_alloc(size,nobj)
	}
}


// 算法:deallocate
// 输入:需要释放的内存块地址p和大小size
{
	if(size 大于128字节)
		直接调用free(p)释放
	else
	{
		将size向上取8的倍数,并据此获取对应的空闲列表表头指针free_list_head
		调整free_list_head将p链入空闲列表块中
	}
}
假设这样一个场景,free_list[2]已经指向了大小为24字节的空闲块链表,如图1所示,当用户向allocator申请21字节大小的内存块时,allocaotr会首先检查free_list[2]并将free_list[2]所指的内存块分配给用户,然后将表头指向下一个可用的空闲块,如图2所示。注意,当内存块在链表上是,前4个字节是用作指向下一个空闲块,当分配给用户时,它是一块普通的内存区。

                        图1 某时刻allocator的状态

                                  图2 分配24字节大小的内存块
4、小结
STL中的内存分配器实际上是基于空闲列表(free list)的分配策略,最主要的特点是通过组织16个空闲列表,对小对象的分配做了优化。
1)小对象的快速分配和释放。当一次性预先分配好一块固定大小的内存池后,对小于128字节的小块内存分配和释放的操作只是一些基本的指针操作,相比于直接调用malloc/free,开销小。
2)避免内存碎片的产生。零乱的内存碎片不仅会浪费内存空间,而且会给OS的内存管理造成压力。
3)尽可能最大化内存的利用率。当内存池尚有的空闲区域不足以分配所需的大小时,分配算法会将其链入到对应的空闲列表中,然后会尝试从空闲列表中寻找是否有合适大小的区域,
但是,这种内存分配器局限于STL容器中使用,并不适合一个通用的内存分配。因为它要求在释放一个内存块时,必须提供这个内存块的大小,以便确定回收到哪个free list中,而STL容器是知道它所需分配的对象大小的,比如上述:
    stl::vector<int> array;
array是知道它需要分配的对象大小为sizeof(int)。一个通用的内存分配器是不需要知道待释放内存的大小的,类似于free(p)。





当兵心理测试软件,当兵心理测试题及答案 心理测试是一种比较先进的测试方法,它是指通过一系列手段,将人的某些心理特征数量化,来衡量个体心理因素水平和个体心理差异差异的一种科学测量方法。小编为你整理了当兵心理测试题及答案,希望对你有所参考帮助。征兵心理测试题(1代表是2代表否)1、我的胃口很好。12、我早上起来的时候,多半觉得睡眠充足,头脑清醒13、我喜欢看报纸上的犯罪新闻。14、有时我常感到困难重重,无法克服。25、我时常遇见一些所谓的专... 阅读详情

相关推荐

ROS2节点通信实战:用C++手写一个‘智能小车’控制模型(附完整代码)

本文详细介绍了如何使用ROS2和C++构建一个智能小车控制模型,涵盖运动控制节点、电池管理服务、参数动态配置和Rviz可视化等核心功能。通过实战项目演示ROS2节点通信机制,帮助开发者快速掌握机器人开发的关键技术,并提供了完整的代码实现和系统集成方案。

weixin_30607029的博客 262

STL源码刨析

1. STL概述 STL起源: 为的就是复用性的提升,减少人力资源的浪费,建立了数据结构与算法的一套标准。 STL所实现的、是依据泛型思维架设起来的一个概念结构。这个以抽象概念〔 abstract concepts)为主体而非以实际类(classes)为主体的结构,形成了一个严谨的接口标准。在此接口之下,任何组件都有最大的独立性,并以所谓迭代器〈 iterator)胶合起来,或以所谓配接器(adapter)互相配接,或以所谓仿函数( functor)动态选择某种策略( policy或strategy) 。

frighting_ing的博客 8263

从零到一:桌面宠物的硬件架构设计与工程实践

本文详细介绍了基于STM32F103C8T6主控平台的桌面宠物机器人硬件架构设计与工程实践。内容涵盖电源管理、舵机控制、PCB布局及系统调试等核心环节,为硬件爱好者提供从零到一的完整开发指南,助力打造稳定可靠的智能桌面伴侣。

alice7model的博客 1113

STL源码剖析

全世界所有的STL实现版本,都源于Alexander Stepanov和Meng Lee完成的原始版本,这份原始版本有Hewlett-Packard Compant(惠普公司)拥有。每一个头文件都有一份声明,允许任何人任意运用、拷贝、修改、传播、贩卖这些代码,无需付费,唯一的条件是必须将声明置于使用者新开发的文件内这份开放源代码的精神,一般统称为GNU(音译为“革奴”),代码GUN isNotUnix。

NickDeCodes的博客 1729

电子发票二维码背后的秘密:10分钟看懂校验码、加密字符含义与防伪设计

本文深入解析电子发票二维码的结构与防伪设计,揭示校验码和加密字符的生成原理及验证方法。通过实际案例和技术细节,帮助财务人员理解电子发票的安全机制,提升防伪识别能力,确保税务合规。

weixin_29248611的博客 530

北航机器学习期末考试试题2020年春

北航机器学习期末考试试题2020春 看csdn上试题收费,积分还挺高,本着共享的理念,把2020春季ML考试的试题公开,若侵权,立删 前8道题10分,第9题20分 决策树采用ID3算法 对宇宙星球是否适合生存分类 SVM的原理;软间隔、硬间隔;以及对非线性样本点分类 集成学习的原理,以及及串行boosting以及bagging的简单概括 K-means与混合高斯模型的异同以及EM算法的原理,如何计算 马尔可夫随机场最大团;马尔可夫随机场的联合概率分布(势函数表示),贝叶斯网络联合概率分布 PCA主成分基于

qq_43343919的博客 5418

STL 源码剖析 总结索引 | 第1章:概论

概论;六大组件功能与应用;语法:临时对象,静态常量整数成员在类内部直接初始化,increment / decrement / dereference 操作符,前闭后开,function call操作符

AsherGu的博客 1569

Java代码实现opc ua 事件订阅和数据变化订阅

OPC UA (Open Platform Communications Unified Architecture) 提供了两种主要的订阅机制:数据变化订阅(Data Change Subscription)和事件订阅(Event Subscription)。这两种订阅机制允许客户端实时接收来自服务器的数据更新或事件通知。

洛阳泰山的博客 2370

STL源码原理分析

STL详解STL介绍空间配置器一级空间配置器二级空间配置器序列式容器vectorlistdeque适配器stackqueueheappriority_queue关联式容器setmultisetmapmultimap非标准容器hash_set(unordered_set)hash_multiset(unordered_multiset)hash_map (unordered_map)hash_multimap(unordered_multimap)常见的面试问答1、说说 vector 和 list 的区别2、

qq_46495964的博客 4145

基于Vivado MIG IP核的DDR3读写实验(top_rom_ddr/ddr_top)

一、前言 关于Vivado MIG IP核详细配置可以参考我之前的文章:基于Vivado MIG IP核的DDR3控制器(DDR3_CONTROL) 关于MIG IP核的用户端的接口时序可以参考这篇文章:XILINX 的 MIG IP(非AXI4)接口时序以及控制 二、实验内容 本次实验的内容主要是通过MIG IP核向DDR3读写数据,DDR3的接口时序由ddr_top模块提供: ddr_top模块的数据来源是wr_fifo,wr_fifo的数据实际来自top_sd_photo模块(本实验仿真

耐心的小黑的博客 3027

MediaPipe 教程:从安装到应用-全网最全

MediaPipe是Google推出的开源框架,专为构建机器学习管道设计,可以高效处理视频、音频等时间序列数据。本文教程从安装到应用逐步讲解: 安装步骤简单,只需通过pip安装mediapipe包并验证版本; 重点演示人体姿态检测功能,可识别33个身体关键点; 提供基础代码实现,包括视频捕获、关键点检测与可视化; 强调模块化开发,将功能封装成类以提高代码复用性。 教程适合初学者,通过清晰指引和实用代码示例,帮助快速实现计算机视觉应用。

FJN110的博客 1563

STL——空间配置器

目录 前言 一.概念 二.优点 三.空间配置器原理 3.1 一级空间配置器 3.2 二级空间配置器 3.2.1 内存池技术 3.2.2 哈希桶技术 四.内存碎片问题 4.1 外碎片 4.2 内碎片 五.具体细节 5.1 申请空间 5.2 填充内存块 5.3 向内存池中索要空间 前言 我们知道STL容器在不断保存...

weixin_57023347的博客 3201

浏览器缓存导致代码不更新?一招解决部署后用户仍看到旧页面的问题

方案效果适用场景文件名哈希永久解决前端工程化项目HTTP缓存头控制精准控制需服务器权限Meta标签部分生效临时补救方案最佳实践:入口HTML禁用缓存,静态资源使用哈希文件名 + 长期缓存,达到「秒级更新」+「高性能」的平衡!

江拥羡橙的博客 810

施磊C++ | 项目实战 | SGI STL二级空间配置器源码剖析

C++SGI STL 内存池二级空间配置器源码剖析

m0_74795952的博客 1201

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【STL源码剖析】【2、空间配置器——allocator】

【STL源码剖析】【2、空间配置器——allocator】

zwh1298454060的博客 1435

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【STL源码剖析】空间配置器

腾讯二面:聊聊STL的空间配置器。 我:?????然后开始聊vector动态扩容,/(ㄒoㄒ)/~~ SGI STL的配置器与众不同,名称是alloc而非allocator。标准的allocator只是对操作符new和delete的一层薄薄的封装,并没有考虑到任何效率上的优化。 一般而言,我们习惯的C++内存配置操作和释放操作是这样的: class Foo {...}; Foo *pf=...

小小小宁波很靠谱 323

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

stl源码剖析_《STL源码剖析》学习笔记——空间配置器

目录1. 空间配置器概述2. 构造和析构基本工具3. 空间的配置与释放,std::alloc4. 内存基本处理工具1. 空间配置器概述从STL的实现角度来看,空间配置器的位置尤为重要,整个STL的操作对象(所有的数值)都是存放在容器之内,而容器一定需要配置空间以存放资料。空间配置器就是为各个容器提供高效的管理空间。SGI STL的配置器与众不同,也与标准规范不同,其名称为alloc而非alloca...

weixin_39636099的博客 104

SGI STL源码剖析——空间配置器

SGI STL源码剖析——空间配置器前言空间配置器SGI空间配置器内存配置和对象构造如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 前言 这段时间读了侯捷老师的STL源码剖析,有一些体会和收获,看书的过程也碰到了许多疑惑,因此将自己的理解记录下来,原书和源码 https:

qq_31082639的博客 1506

《STL 源码剖析》——空间配置器alloc

栈和队列是应用最多的数据结构之二,有数组实现和链表实现两种方式。当需要对容器做出限制,只允许一边插入和取出数据时,则需要用到栈。下面将总结数组实现的栈和阐述其原理。 一、线性表——栈Stack 1.1栈Stack定义 栈是一种特殊的线性表,其插入(也称为入栈或压栈)和删除(也称为弹出或出栈)操作都在表的同一端进行;该插入和删除的端口称为栈顶(top),另一端称为栈底(bottom)。 1.2栈的基本运算 1.2.1基本运算 (1) 初始化(构造一个空的栈) (2) 计算栈长度(栈中节点个数) (3) 插入节

净无邪博客 1449

C/C++编程:STL空间配置器源码剖析

何为空间配置器 为何需要先了解空间配置器 从使用STL层面而言,空间配置器并不需要介绍,因为容器底层都封装好了,但是如果从STL实现角度出发,空间配置器是必须先了解的。 作为STL设计背后的支撑,空间配置器总是在默默付出着。为什么你可以使用算法来高效的处理数据,为什么你可以对容器进行各种操作,为什么你可以使用的迭代器遍历空间,这一切的一切,都有“空间配置器”的功劳 SGI STL 专属空间配置器 SGI STL 的空间配置器与众不同,且与 STL 标准规范不同。 其名为alloc,而非allocator 虽

OceanStar的博客 601

SGI STL二级空间配置器源码剖析

从上面可以看到__STL_DEFAULT_ALLOCATOR通过宏控制有两种实现,一种是allocator< T >,另一种。管理内存,和C++标准库中提供的allocator是一样的,但其二级空间配置器allocator采用了基于freelist。SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用malloc和free来。是alloc,这两种分别就是SGI STL的一级空间配置器和二级空间配置器的实现。二级空间配置器分配空间流程。

qq_43804905的博客 160

C++ STL : SGI-STL空间配置器源码剖析

文章目录空间配置器的概念SGI-STL空间配置器一级空间配置器二级空间配置器申请空间补充内存块从内存池中索要空间空间回收内存碎片外碎片内碎片空间配置器的再次封装 空间配置器的概念 空间配置器,顾名思义就是为各个容器高效的管理空间(空间的申请与回收) 的,在默默地工作。 在之前所有模拟实现的容器中,对于空间的管理都是通过直接调用new和delete来进行的,虽然代码可以正常运行,但是还是存在着大量的缺点。 空间申请与释放需要用户自己管理,容易造成内存泄漏 频繁向系统申请小块内存块,容易造成内存碎片 频繁

凌桓丶的博客 1656

STL源码剖析--空间配置器

空间配置器是最不需要介绍的东西,他总是隐藏在容器(container)的背后,默默工作,默默付出。 allocator 之所以说是空间配置器而不是内存配置器,因为空间不一定是内存,也可以是磁盘或者其它辅助存储介质。 空间配置器的标准接口 allocator::allocator() default constructor allocator: :allocator (const allocato...

lvxin15353715790的博客 277
上一篇: 大端模式和小端模式
下一篇: STL源码剖析---vector
hackbuteer1
博客等级 码龄15年 1万+粉丝 251原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值