C++学习记录——삼십삽 STL空间配置器

news2024/12/1 0:49:11

文章目录

  • 1、概念
  • 2、使用
  • 3、容器上的体现


1、概念

我们先看malloc,malloc是创建在堆上的,虽然malloc可以申请内存,但也有限制,windows下用VirtualAlloc可以直接向堆申请内存,Linux中则是brk,不过这两个效率一般。

malloc向堆申请函数,它本身是个内存池,只是这个内存池面向整个程序。空间配置器运行在malloc之上,是一个小的内存池,面向STL的容器。STL的容器可以使用空间配置来开辟空间,但空间配置器是20多年前的代码了,到现在也没有更新多少,核心功能,一点细节变一变就是了。空间配置器不能用于别的结构,只能用于STL容器。

为什么STL容器需要空间配置器?因为它需要频繁地申请和释放内存,如果只用malloc,效率不是很高,malloc是服务于所有程序的,并不是专用于STL容器的。频繁使用malloc,容易造成系统碎片,虽然空间配置器也没很好地解决这个问题;使用malloc时,会有额外空间来记录当前空间大小。

主要问题是效率问题

2、使用

如果用户所需字节数大于128,就使用一级空间配置器,如果不是,就使用二级配置器。

在STL的源码中,一级配置器是__malloc_alloc_template,二级配置器是__default_alloc_template。

一级空间配置器中

在这里插入图片描述

allocate就是malloc的工作,deallocate就是free的工作,不过如果malloc失败,就会调用oom_malloc的函数,reallocate也是一样。这几个函数时public的,这些代码上面,是oom_malloc的声明,以及一个宏。

在这里插入图片描述

在代码下方

在这里插入图片描述

oom_malloc先去调用了一个函数指针__malloc_alloc_oom_handler,如果失败,就抛异常,是一个宏__THROW_BAD_ALLOC,如果成功,那就再去调用这个函数,也就是(*my_malloc_handler),最后返回结果,调用的这个函数里应当是做了释放空间操作,不过这个调用的函数默认为空。

所以这个一级空间配置器是malloc和free的封装,如果失败就抛异常,整体上和operator new的实现相似。

二级空间配置器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

C++中提倡用枚举,const,内联替代宏,如果大于128,就去调用一级空间适配器了。如果不是,那就是二级,二级里主要内容是一个内存池和哈希桶,对应下图的start_free,end_free,heap_size,和free_list两个。

在这里插入图片描述

哈希桶是一个指针数组,__VOLATILE就是volatile。实际上,空间配置器所操作的内存都源于malloc,前面也看到,malloc失败就去找空间配置器,大于128就走一级,小于则来到二级。二级空间配置器里,有两个指针start和end指向一块空间的头尾,这块空间是提前准备好的,如果请求十字节内容,start就往后走,让出十字节空间,然后给到外面,走完了就重开一块空间。那么程序归还空间的时候,这些借出去的空间应当如何管理?每一块空间基本都是不一样的大小,我们可以把它们用链表连接起来,当再使用这些空间的时候,要如何找到合适大小的空间?所以如果这样管理就有些麻烦。源码中对归还的空间是利用哈希桶来管理的。

在这里插入图片描述

这里的办法和磁盘往外IO时的策略相似,向上对齐到8字节。如果申请了9到16个字节,那就去找1号桶。最开始的时候,所有的桶都没有字节数,start和end是空,如果申请了10字节,走二级空间配置器,然后找到了1号桶,如果发现1号桶是空0,就会去找内存池要,也就是start和end之间的内存池,进行malloc,malloc不会只获取16字节,会多给一点。申请10字节,因为在1号桶,所以申请了16字节,并且继续申请了字节,具体是多少个看代码实现。现在申请的是10字节,代码可能申请了30字节,把10字节返回后,就把剩余的空间挂在1号桶这里,并且有指针指向这个桶,那么下次再找1号桶时1号桶就有空间了,头删链表来把空间送出去。

释放内存时,需要传空间大小,大于128就走一级空间配置器,小于就走二级空间配置器,把这块空间给头插进对应的链表,这里找桶的位置就是通过空间大小来找的,使用前和使用后空间大小不变,所以就能找到正确的桶。等再次申请时,还是找这些已经开好的空间,去对应的桶拿空间就好,如果一个桶空间没有了,那就去找内存池分配一些空间。

每个桶都是8字节,128字节的话总共需要14个8字节,也就是数组是14个元素。每个桶是如何存空间的?源码中使用了联合体,联合体有一个指针,占4个字节,每个空间都会被强转成这个联合体类型,每次都只用去看前4个字节就可以,64位下指针大小是8字节,所以每个桶都是8字节。被连接起来的空间,前一个空间的4个字节存储下一个空间的前4个字节,用的时候就拿出去第一个空间,然后对应桶指向第二个空间,归还时又重新回到之前的连接。哈希桶结构可以很好地找到对应的空间。

假设代表48字节的桶没有空间,内存池也没有空间,malloc也失败了,那么这条路线上全部失败,应该抛异常了,但空间配置器没有这么做,而是去找后面几个位置是否有空间,有的话就切割出大于48字节的一部分空间,给48号桶。

每一个桶连接的空间,不同程序都可以使用同样的空间,因为既然是一个桶,那么使用的字节都够用。从桶中拿空间这个操作是在加锁后进行的,这个加锁通过类来实现,完成这些加锁操作,桶指向下一个空间后,就出了作用域,就析构了。这就是一个RAII。

一个进程只有一个空间配置器,所以空间配置器其实可以设计单例模式的,源码中虽然没有设计成单例模式,但基本上所有成员函数都是静态的,是间接的单例。

空间配置器能一定程度上解决内存碎片问题。内存在频繁申请释放后,一些小块内存夹杂在很多内存之间,导致越来越难以申请连续的大块内存。空间配置器是申请一大块内存后,自己拿来反复拿取,通过上面的操作,能解决一点内存碎片问题。这些是外碎片问题,还有内碎片问题。比如申请12个字节,按照空间配置器,我就得找1号桶,申请16字节,所以也是申请了多余的内存,这就是内碎片问题。

3、容器上的体现

比如列表,除了传T模板参数,还会传一个alloc模板参数

在这里插入图片描述

默认传一个二级配置器,一级嵌套在二级里面,如果大于128,就走一级。

在这里插入图片描述

这个图的前两行就是专门针对list_node——allocator的配置器,get_node函数里针对link_type类型对象的其中一个data值进行了单独调用了一个函数,而析构也是调用了一个单独的destroy的函数

在这里插入图片描述

而上面的几个图中有个simple_alloc函数,也有专门的类

在这里插入图片描述

所以链表申请节点就是调用的create_node函数,里面再调用get_node函数,simple_alloc就是对二级空间配置器的封装,里面有二级的申请和释放。如果没有内存,那就申请一个节点大小的内存,按照类型去new一个空间。

看上面的源码就能逐渐明白原理。

结束。

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

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

相关文章

HCIA自学笔记01-传输介质

通信网络除了包含通信设备本身之外,还包含连接这些设备的传输介质,如同轴电缆、双绞线和光纤等。不同的传输介质具有不同的特性,这些特性直接影响到通信的诸多方面,如线路编码方式、传输速度和传输距离等。 简单网络:…

✔ ★算法基础笔记(Acwing)(一)—— 基础算法(20道题)【java版本】

基础算法 一、快速排序1. 快速排序例题2. 第k个数( 快速选择 ) ✔ ✔1.31★快排二刷总结( 4点 ) 二、归并排序1. 归并排序模板题 ✔ ✔1.31★二刷总结 ★2. 逆序对的数量 ✔ ✔1.31★二刷总结 三、二分1. 数的范围 ✔1.31★二刷总结(mid > x 则是 输出最左边一个)第一个大于…

【操作系统】聊聊Linux内存工作机制

内存主要是用来存储系统和应用程序的指令、数据、缓存等 内存映射 内存是需要安全机制保护的,所以只有内核才可以直接访问物理内存。进程如果要访问内存需要通过独立的虚拟地址空间。 虚拟地址空间其实包含两部分。一部分是内核空间,另一部分就是用户…

搭建RabbitMQ消息服务,整合SpringBoot实现收发消息

作者主页:Designer 小郑 作者简介:3年JAVA全栈开发经验,专注JAVA技术、系统定制、远程指导,致力于企业数字化转型,CSDN博客专家,蓝桥云课认证讲师。 目录 一、前言1.1 什么是消息队列1.2 RabbitMQ 是什么1.…

【AI】机器学习——线性模型(线性回归)

线性模型既能体现出重要的基本思想,又能构造出功能更加强大的非线性模型 文章目录 3.1 线性模型3.1.1 数据3.1.2 目标/应用 3.2 线性回归3.2.1 回归模型历史3.2.2 回归分析研究内容回归分析步骤 3.2.3 回归分析分类3.2.4 回归模型3.2.5 损失函数梯度下降法一元回归模…

【数据仓库基础(二)】数据仓库架构

文章目录 一. 基本架构二. 主要数据仓库架构1. 数据集市架构1.1. 独立数据集市1.2. 从属数据集市1.3. Inmon企业信息工厂架构 2. Kimball数据仓库架构3. 混合型数据仓库架构 三. 操作数据存储(ODS) 一. 基本架构 架构是指系统的一个或多个结构。结构中包…

stride与padding对输出尺寸的计算

公式: 练习: 图1: input4,filter3,padding0,stride1 output2 图2: input5,filter3,padding0,stride2 output2 图3: input6,filter3&am…

设计模式之观察者模式、访问者模式与模板方法模式

目录 观察者模式 简介 优缺点 结构 实现 运用场景 访问者模式 简介 优缺点 结构 实现 运用场景 模板方法模式 简介 优缺点 结构 实现 运用场景 观察者模式 简介 又叫发布-订阅模式,定义对象间一种一对多的依赖关系,使得每当一个对象改…

Android 应用程序通过MediaPipe 图片识别

MediaPipe 中使用目标检测模型可以实现实时检测图像或视频中的物体,并标记出物体的位置和类别。MediaPipe 中的目标检测模型基于机器学习算法,经过训练以识别特定的物体类别; 以下是在 Android 应用程序中集成 MediaPipe Object Detection 的…

SpringMVC应用

文章目录 一、常用注解二、参数传递2.1 基础类型String2.2 复杂类型2.3 RequestParam2.4.路径传参 PathVariable2.4 Json数据传参 RequestBody2.5 RequestHeader 三、方法返回值3.1 void3.2 Stringmodel3.3 ModelAndView 一、常用注解 SpringMVC是一个基于Java的Web框架&#…

Nacos启动连接mysql报错

问题 Nacos启动后,访问http://localhost:8848/nacos/index.html一直访问不了,查看nacos安装目录下的logs/config-fatal.log日志文件发现连接mysql报错,但是通过客户端连接工具测试mysql连接正常;核心报错如下: Cause…

【线程池】面试被问到线程池参数如何配置时该如何回答

前言 没有基于业务场景,直接抛出这个问题,等同于耍流氓。 八股文告诉我们CPU密集型就核心数1,IO密集型就核心数*2,那么真实业务中该怎么去配置呢。 方法论还是有的 1.需要分析线程池执行的任务的特性: CPU 密集型还是 …

【操作】安防监控/视频汇聚/视频云存储EasyCVR平台AI智能分析网关V3接入教程2.0

TSINGSEE的边缘计算硬件智能分析网关V3内置多种AI算法模型,包括人脸、人体、车辆、车牌、行为分析、烟火、入侵、聚集、安全帽、反光衣等等,可应用在安全生产、通用园区、智慧食安、智慧城管、智慧煤矿等场景中。将网关硬件结合TSINGSEE青犀的视频汇聚/安…

数据结构-01 数据结构基本概念,算法时间复杂度,空间复杂度

0 数据结构概述 四门课的关系 1 绪论 数据对象、数据元素、数据项关系 1.1 数据结构的基本概念 1.2 算法和算法评价 小练习 空间复杂度中的递归调用 n只是传入 n也是数组,计算存储数组flag的空间大小

HTTPS协议和SOCKS5协议的区别

HTTPS协议和SOCKS5协议是两种不同的网络协议,它们在传输数据的方式、安全性和使用场景等方面都有所不同。下面将介绍HTTPS协议与SOCKS5协议的区别。 传输数据的方式 HTTPS协议是一种基于HTTP协议的安全协议,它使用SSL/TLS协议对数据进行加密和解密。在传…

Kafka3.0.0版本——消费者(独立消费者消费某一个主题数据案例__订阅主题)

目录 一、独立消费者消费某一个主题数据案例1.1、案例需求1.2、案例代码1.3、测试 一、独立消费者消费某一个主题数据案例 1.1、案例需求 创建一个独立消费者,消费firstTopic主题中数据,所下图所示: 注意:在消费者 API 代码中必…

时序预测 | MATLAB实现CNN-LSTM卷积长短期记忆神经网络时间序列预测(风电功率预测)

时序预测 | MATLAB实现CNN-LSTM卷积长短期记忆神经网络时间序列预测(风电功率预测) 目录 时序预测 | MATLAB实现CNN-LSTM卷积长短期记忆神经网络时间序列预测(风电功率预测)预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1…

Matlab 如何把频谱图的纵坐标设置为分贝刻度

Matlab 如何把频谱图的纵坐标设置为分贝刻度 Matlab代码如下: % 如何把频谱图的纵坐标设置为分贝刻度 % % pr2_2_6 clc; clear; close all;load pr2_2_6_sndata1.mat % 读入数据 X fft(y); % FFT n2 1:L/21; % 计算正频率…

天翼云不做备案接入,如何绑定域名,不用80端口,443端口。

443,80端口不开启。 第一步: 宝塔更改web端口 搞个复杂的端口。 第二步: 在天翼云策略组上面开启修改过的web端口。 第三步:接入cdn,端口改成修改过的端口。

EVA: Visual Representation Fantasies from BAAI

本文做个简单总结,博主不是做自监督领域的,如果错误,欢迎指正。 链接 Code: Official:baaivision/EVA MMpretrain:open-mmlab/mmpretrain/tree/main/configs/eva02 Paper: EVA01:…