STL源码剖析-分配器 Allocator

news2025/1/20 18:28:19

分配器(Allocator)

分配器给容器用的,是一个幕后英雄的角色。分配器的效率非常重要。因为容器必然会使用到分配器来负责内存的分配,它的性能至关重要。
在这里插入图片描述

在C++中,内存分配和操作通过new和delete完成。

new中包含两个操作,第一步是使用operator new分配内存,第二步是调用构造函数;
delete中包含两个操作,第一步是调用析构函数,第二步是使用operator delete释放内存。

operator new() 和 malloc()

vc98

C++的内存分配动作最终都会回到malloc,malloc再根据不同的操作系统类型(Windows,Linux,Unix等)底层的系统API来获取内存

同时我们可以看到,malloc分配之后的内存块中不是只有数据,而是还包含了其它很多数据。这样容易联想到如果分配次数越多,那么内存中数据越零散,这些额外的数据开销就越大。

所以一个优秀的分配器,应当尽可能的让这些额外的空间占比更小,让速度更快。
在这里插入图片描述

VC6,BC5,GC2.9所带的标准库分配器源码分析

VC6

在这里插入图片描述

BC5

BC5的分配器与VC6没有本质区别。BC5的优点是他的分配器第二参数有一个默认值,让我们在调用分配器时方便了一些。
在这里插入图片描述

GC2.9

GC2.9自带的allocator也差不多
在这里插入图片描述
虽然GC2.9和上面也基本一致,但是它有额外声明不要使用这个标准库的分配器,同时这个标准库分配器没有被使用。它使用的分配器是自行修改的

GC2.9的分配器的效率提高思路

GC2.9使用的是一个叫alloc的分配器
1.内存空间简介
在这里插入图片描述
2.G2.9 分配器——alloc
malloc分配出的内存区块中需要有地方来存放这个内存区块的大小。然而对于同一个容器而言,它的内置类型应当是相同的,所以对于容器的分配器,我们可以对此作出优化。

alloc创建了16条单向链表用来存放数据。这些单向链表用来存放不同元素大小的数据。
当容器需要内存时,alloc先查看自己是否已经申请过了这个大小的内存,如果已经申请过了,那么就继续放在对应的单向链表尾部。否则再调用malloc向系统申请一块内存空间。具体可以查看这里【C++内存管理】G2.9 std::alloc 运行模式
它的优点就是,由于每个链表都只有一种大小的元素,那么对于这条链表上的每一个元素,我们就不必再单独使用内存空间来记录它的大小。从而节省了内存空间

#0所对应的节点连接的链表负责分配大小为8byte的子空间
#3所对应的节点连接的链表负责分配大小为32byte的子空间
以此以8byte的间隔向后类推
#15所对应的节点连接的链表负责分配大小为128byte的子空间

在这张图中可以看到很多看起来非常杂乱的连线,这个实际上是alloc的内存申请机制影响的,alloc在申请内存时会考虑之前剩余下来的内存余量(这里存在pool当中),如果有内存余量的话在下一次申请空间时,会将上一次分配剩下来的内存空间按照需要的大小进行切割并挂载到对应的节点上。如果上一次剩余的大小不足以划分,那么会将这个剩余的内存空间挂到与它相等的内存空间大小的节点上去,然后重新分配内存。

二级分配器

在这里插入图片描述

当需要一次性分配的内存超过了128byte,std::alloc()本身就不会为其服务,而会将这个需求转给其他函数去处理,这里我们会在后边剖析源码的时候去介绍

可是用户申请分配的空间可能并不会正好是8的倍数(通常都不是),这时,就会把他提升至最近的长度,并为其分配对应大小的内存块。

new运算分两个阶段

(1)调用::operator new配置内存;
(2)调用对象构造函数构造对象内容

delete运算分两个阶段

(1)调用对象析构函数;
(2)调用::operator delete释放内存
为了精密分工,STL allocator将两个阶段操作区分开来:
内存配置有alloc::allocate()负责,内存释放由alloc::deallocate()负责;
对象构造由::construct()负责,对象析构由::destroy()负责。
同时为了提升内存管理的效率,减少申请小内存造成的内存碎片问题,SGI STL采用了两级配置器
当分配的空间大小超过128B时,会使用第一级空间配置器;当分配的空间大小小于128B时,将使用第二级空间配置器。

第一级空间配置器直接使用malloc()、realloc()、free()函数进行内存空间的分配和释放,而第二级空间配置器采用了内存池技术,通过空闲链表来管理内存。
当然,alloc也可以直接作为第一级分配器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/427657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML5 Input 类型

文章目录HTML5 Input 类型Input 类型: colorInput 类型: dateInput 类型: datetimeInput 类型: datetime-localInput 类型: emailInput 类型: monthInput 类型: numberInput 类型: rangeInput 类型: searchInput 类型: telInput 类型: timeInput 类型: urlInput 类型: weekHTML…

手撕哈希表

🌈感谢阅读East-sunrise学习分享——[进阶数据结构]哈希表 博主水平有限,如有差错,欢迎斧正🙏感谢有你 码字不易,若有收获,期待你的点赞关注💙我们一起进步🚀 🌈我们上一…

SNN demo

记录一个同门给的SNN demo,仅供自己参考 1 SNN和ANN代码的差别 SNN和ANN的深度学习demo还是差一些的,主要有下面几个: 输入差一个时间维度T,比如:在cv中,ANN的输入是:[B, C, W, H]&#xff0c…

Spring WebFlow-远程代码执行漏洞(CVE-2017-4971)

Spring WebFlow-远程代码执行漏洞(CVE-2017-4971) 0x00 前言 Spring WebFlow 是一个适用于开发基于流程的应用程序的框架(如购物逻辑),可以将流程的定义和实现流程行为的类和视图分离开来。在其 2.4.x 版本中&#x…

浅说情绪控制被杏仁体劫持

2023年4月16号,没想到被杏仁体劫持那么严重,触发手抖和口干的症状,这个还真是自己万万没有想到的。 人生要修炼两条线:一条明线是做的事情,那是自己要做的具体事情。 一条暗线是修炼的自己,这次也做了测试…

云安全——Docker Daemon

0x00 前言 其他云安全相关内容,请参考:云安全知识整理 0x01 Docker Daemon Daemon是Docker的守护进程,Docker Client通过命令行与Docker Damon通信,完成Docker相关操作,2375端口是Daemon的未授权端口。 0x01 2375 …

设计模式之监听模式

本文将会介绍设计模式中的监听模式。   监听模式是一种一对多的关系,可以有任意个(一个或多个)观察者对象同时监听某一个对象。监听的对象叫观察者(Observer),被监听的对象叫作被观察者(Obser…

QObject对象生命周期管理

QObject对象生命周期管理 1.C中对象的生命周期管理是一个非常重要的话题,因为C需要程序员自己手动管理内存,而这也是C程序经常容易出现内存问题的重要原因。 1.1 特别是多线程环境下如何正确管理好对象的生命周期,更是C程序开发中的一个难点…

对抗样本-(CVPR 2022)-通过基于对象多样化输入来提高有针对性对抗样本的可迁移性

论文地址:https://arxiv.org/abs/2203.09123 代码地址:https://github.com/dreamflake/ODI 摘要:本文提出了一种新的方法来生成有针对性的对抗样本,该方法通过使用多种不同的输入图像来生成更加丰富和多样化的图像。具体而言&…

hashlib模块

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 hashlib模块专栏:《python从入门到实战》 哈希算法,也叫摘要算法。 加密&…

Postcat 插件上线,支持 ApiPost 格式导入

作为开源的 API 管理工具,Postcat 已经支持 Postman、swagger、Eolink 等平台的数据导入导出。 前不久有用户跟我们提需求,想要 Postcat 支持国内的一些主流的 API 管理工具,好消息是现在不就支持了么! 最近我们的插件广场上线了一…

etcd概述

本文主要介绍了 etcd 相关概念,以及 etcd 的主要使用场景 1. 介绍 etcd 是云原生架构中的基础组件,由 CNCF 孵化托管。etcd 在微服务和 kubernetes 集群中不仅可以作为服务注册中心用于服务发现,还可以作为 key-value 存储中间件etcd 是 Co…

Spring的Bean初始化过程和生命周期

Spring的Bean初始化过程和生命周期一、Spring创建bean的流程图二、Spring创建bean的详细流程1.加载bean信息2.实例化bean3.bean属性填充4.初始化bean5.后置操作三、bean的生命周期四、总结Spring的核心功能有三点IOC、DI、AOP,IOC则是基础,也是Spring功能…

Python+Requests模拟发送post请求

模拟发送post请求 发送post请求的基础知识dumps和loads 代码示例: # 发送post请求 import requests,json # 发送post请求的基础知识dumps和loads str_dict {name:xiaoming,age:20,sex:男} print(type(str_dict)) str1 json.dumps(str_dict) # 1,json.dumps 是把…

git 本地新建并提交上传仓库

初始化步骤基本解释 新建readme touch README.md 初始化仓库 git init 添加仓库下所有文件 git add . 提交 备注到本地 git commit -m "备注" 链接远程git库 git remote add origin 新建库ssh链接 上传代码 git push -u origin master 初始化操作步骤 touch README.…

【Ubuntu】Ubuntu20基础配置+go开发配置

这里写自定义目录标题1 基础配置1.1 安装ifconfig网络管理工具1.2 初始化root密码1.3 换镜像源1.4 关闭息屏休眠1.5 关闭自动更新2 开发环境2.1 go2.1.1 建立软件目录并安装软件2.1.2 建立go工作目录2.1.3 配置环境变量2.2 mysql2.2.1 安装2.2.2 建立对外用户并更改密码2.2.3 修…

江苏三年制专转本法学类考纲配套课程网课题库

江苏三年制专转本法学类考纲配套课程网课题库1、江苏专转本的考试科目都有哪些? 2022年开始江苏专转本成绩主要由语文/数学英语/日语专业课三科的成绩构成,满分500分。分别给大家解释一下 语文/数学:满分150分(文科考语文&#xf…

[源码解析]socket系统调用上

文章目录socket函数API内核源码sock_createinet_createsock_allocsock_map_fd相关数据结构本文将以socket函数为例,分析它在Linux5.12.10内核中的实现,先观此图,宏观上把握它在内核中的函数调用关系:socket函数API socket 函数原…

王小川,才是深「爱」李彦宏的那个人?

在推出中国首个类ChatGPT产品「文心一言」后,李彦宏在接受专访时断言,中国基本不会再出一个OpenAI了,「创业公司重新做一个ChatGPT其实没有多大意义,基于大语言模型开发应用机会很大,没有必要再重新发明一遍轮子。」 听…

【AI理论学习】深入理解扩散模型:Diffusion Models(DDPM)(理论篇)

深入理解扩散模型:Diffusion Models引言扩散模型的原理扩散过程反向过程优化目标模型设计代码实现Stable Diffusion、DALL-E、Imagen背后共同的套路Stable DiffusionDALL-E seriesImagenText encoderDecoder什么是FID(Frechet Inception Distance&#x…