C++附加篇: 空间适配器

news2024/11/15 21:38:16

 "我有时难过,却还有些抚慰和感动。"

一、我们来谈谈空间适配器        

(1) 什么是空间配置器?

        STL的六大组件,容器、算法、迭代器、适配器、仿函数,最后一个也就是"空间适配器"。

        所谓"空间适配器",顾名思义,就是对STL中各个容器的内存进行高效的管理。也许你会说,诶,我写了这么多的C++代码,为什么没有这个概念呢?或者说,为什么我们根本没有见到!这个空间适配器呢?

        然而事实上,不是说,我们没有使用,而是在我们使用诸如vector\list\deque时,我们的空间配置器是在默默地为我们进行工作。

(2) 为什么需要空间适配器呢?

        我们使用堆上的空间,管它三七二十一,直接malloc 或者new不就得了?为什么还需要在空间申请的过程里,添加这一个适配器呢?对于使用者而言不麻烦吗?对于设计者而言,不也会给他们带来麻烦嘛?

        是的,如果我们仅单单从学习语言的角度来看,似乎无脑用malloc、new并没有啥有待商榷的地方,毕竟那本来就是提供给应用层调用的函数。

        但如果站在系统层面上,也许你在语言层调用malloc、new只是看到了单单的函数调用,并你接收到了来自函数的返回值"void*",你就可以针对这一块对空间上的内存块进行操作,仅此而已。你根本不知道操作系统在底层为你的行为做了哪些操作。

 唔,大概在底层,操作系统会为你做如下的事情:

        如果是在Windos下,malloc\new在底层会去调用 VirtualAlloc 向操作系统申请堆空间,如果是在Linux下,malloc、new会在底层调用 brk或者 mmap得到堆空间的起始地址。

        这似乎很符合我们的预期,与maloc、new相比,不就多调用了一次函数而已? 但事实真的是这样嘛?

        我们以在Linux环境下申请、释放空间例举:

我们以ARM64架构下来划分虚拟进程地址空间,编制从全0~全F。

高16位(0xFFFF 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF) -->  内核地址空间

低16位(0x0000 0000 0000 0000 ~ 0x0000 FFFF FFFF FFFF) --> 用户地址空间

        不管我们使用什么样的函数,一旦涉及到要使用系统资源,例如: 堆空间、文件描述符、套接字描述符…… 其底层都需要访问系统提供的接口函数。然而,用户是不能直接执行内核代码的,而是需要切换成 内核用户才能执行代码,这个过程也叫做 "陷入内核",将用户态切换为内核态。显然,这个过程是很耗时的。

        不仅如此,Linux有自己内部的内存管理系统,如"伙伴系统",它需不需要维护系统堆空间上的资源?需要!难道它直接就把那块内存块扔给 用户?需不需要调剩余内存块的结构呢? 它需不需要对释放完的内存块进行管理,以避免内存碎片问题……

        有了上面的论述,空间适配器的出现,也就具有必然性。

malloc\new的不足之处

① 空间申请与释放需要用户自己管理,容易造成内存泄漏

频繁向系统申请小块内存块,容易造成内存碎片

频繁向系统申请小块内存,影响程序运行效率

④ 未考虑线程安全问题。

⑤ 代码结构比较混乱,代码复用率不高。

        因此需要设计一块高效的内存管理机制。


二、空间配置器窥探源码

(1) 空间适配器原理

        以上提及的用new、malloc最主要的一个问题是,"频繁"二字,在SGI版本中,空间配置器
以128作为 小块内存 与 大块内存的分割线。由此,其空间分配的结构分为两个的等级:一级空间配置器用于处理 大块内存的申请、释放,二级空间配置器用于处理 小块内存的申请、释放。

(2) 具体实现

一级适配器:

        一级适配器原理很简单,就是一个对malloc、free简单的封装。

         例如这里一个simple_alloc 使用这个适配器。

二级适配器:

        我们在前面说SGI版本的Alloc,对于二级适配器而言,是一个管理这1~128这个范围的内存块。那么如何管理这一堆切小的小块内存呢,SGI采用了哈希桶的方式进行管理。但是,1~128,难道需要我们用开128个桶的空间来管理嘛?答案是否定的,第一个是从使用上来说,大多数开辟空间的大小都是4的正数倍,其次是,如果对内存空间的管理过于细腻,必定会造成一定空间浪费的问题。因此,SGI-STL将用户申请的内存块,向上对齐按照8byte。

         此时,我们原本需要128个桶来唯一标识一个内存块对应的挂接位置,变为只需要16个桶。

  // 计算对齐后的 大小
  static size_t ROUND_UP(size_t bytes) {
        return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
  }

    
  // 计算该字节大小 对应哪个桶
  static  size_t FREELIST_INDEX(size_t bytes) {
        return (((bytes) + __ALIGN-1)/__ALIGN - 1);
  }

        STI-STL提供了两个函数,分别可用来计算 对齐字节大小 和 内存块挂接的桶位置。

refill与chunk_alloc: 

        二级适配器还考虑了多线程环境下,Alloc的场景。 

(3) 空间适配器与具体容器


三、 如何理解STL?

        STL的六大组件包括,算法、迭代器、容器、适配器、分配器(空间配置器)、仿函数。这几者有何关联呢?


总结:

        空间配置器其底层技术就是采用的池化技术,可以说就是一个小型的内存池。能在频繁申请小块内存的场景中,提高一定的性能。

        STL六大组件:算法、迭代器、容器、适配器、分配器(空间配置器)、仿函数。

本篇到此结束,感谢你的阅读

祝你好运,向阳而生~

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

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

相关文章

轻松掌握K8S使用kubectl操作配置文件挂载ConfigMap和密钥Secret知识点05

1、挂载应用配置文件配置集ConfigMap 当有许多应用如redis、mysql,希望将它的配置文件挂载出去,以便随时修改,可以用ConfigMap配置集 具体用法查看使用命令行操作里的 3、ConfigMap配置集实战 2、挂载应用配置文件的敏感信息Secret Secre…

JAVA开发运维(云基础设备监控)

在大型的商用系统中,经常需要监控云设备的健康状态,性能情况,流量数据等。及时发现系统问题,及时修复,以确保系统的高可用。检查云资源的工作内容主要包括基础监控、主动拨测、用户体验、APM监控、指标体系、业务分析、…

Java运行时内存管理

一、前言 希望能在我们平时开发写代码的时候,能够知道当前写的这段代码,内存方面是如何分配的。 我们深知,一个Java程序员在很多时候根本不用操心内存的释放,而是依靠JVM去管理,以前写C代码的时候,却要时刻…

SAP 自定义生产订单状态

1、生产订单通常系统有一整套订单状态,做PP的各位同学都应该知道。 CRTD状态 REL已下达 CNF已报工 DLV已入库 TECO技术性完成 等等状态这里就不在罗列了,可以自行在生产订单中看到 2、这篇文章主要是在生产订单系统外,在自定义一套状态。这个…

Spring更简单的读取和存储Bean(基于注解)

目录 ①从Maven中央仓库获取spring-context和spring-beans的依赖,将依赖引入到pom.xml中 ②配置扫描路径 ③添加注解存储Bean对象(可以使用5大类注解和方法注解) 类注解(写在类上,作用于类上) Contro…

【致敬未来的攻城狮计划】— 连续打卡第十一天:FSP固件库开发点亮第一个灯。

系列文章目录 1.连续打卡第一天:提前对CPK_RA2E1是瑞萨RA系列开发板的初体验,了解一下 2.开发环境的选择和调试(从零开始,加油) 3.欲速则不达,今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

leetcode刷题--辅助工具

idea插件 插件商店搜索leetcode,可以让你利用idea调试leetcode的题目 插件首先需要填写用户名密码登录,登录上就可以在idea搜题、做题、提交等 注意: 一些版本登录可能登录失败,解决方法是换leetcode地址为leetcode.cn。 有些可…

通过用户名密码认证保障 MQTT 接入安全

认证是一种安全措施,用于识别用户并验证他们是否有权访问系统或服务器。它能够保护系统免受未经授权的访问,确保只有经过验证的用户才能使用系统。 物联网连接万物,对试图访问基础设施的用户进行认证至关重要。未经授权的访问存在重大的安全…

数据保管库的数据质量错误

数据保管库的数据质量错误 在过去的几年里,数据仓库发生了巨大的变化,但这并不意味着支撑健全数据架构的基本原理需要被抛在窗外。事实上,随着GDPR等数据法规的日益严格以及对优化技术成本的重新重视,我们现在看到了“Data Vault…

设计模式之备忘录模式(C++)

作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、备忘录模式是什么? 备忘录模式是一种行为型的软件设计模式,在不破坏封装的前提下,获取一个…

OpenCV实例(八)行人跟踪

OpenCV实例(八)行人跟踪 1.目标跟踪概述2.基于背景差分检测运动物体2.1 实现基本背景差分器2.2 使用MOG背景差分器2.3 使用卡尔曼滤波器寻找运动趋势 3.跟踪行人 作者:Xiou 1.目标跟踪概述 目标跟踪是对摄像头视频中的移动目标进行定位的过…

数据结构与算法基础-学习-20-查找之散列表(HASH TABLE)

目录 目录 一、基本思想 二、术语 1、散列方法 2、散列函数 3、散列表 4、冲突 5、同义词 三、如何减少哈希冲突 四、构造散列函数需考虑的情况 五、散列函数的构造方法 1、直接定址法 2、除留余数法 六、如何处理哈希冲突 1、开地址法 2、拉链法 七、散列表查…

【微服务笔记16】微服务组件之Gateway服务网关基础环境搭建、高可用网关环境搭建

这篇文章,主要介绍微服务组件之Gateway服务网关基础环境搭建、高可用网关环境搭建。 目录 一、Gateway服务网关 1.1、什么是Gateway 1.2、Gateway基础环境搭建 (1)基础环境介绍 (2)引入依赖 (3&#…

快速上手Navicat~

众所周知, Navicat是一款轻量级的用于MySQL连接和管理的工具,非常好用,使用起来方便快捷,简洁。下面我会简单的讲一下其安装以及使用的方法。并且会附带相关的永久安装教程。 简介 一般我们在开发过程中是离不开数据库的&#xf…

【Unity VR开发】结合VRTK4.0:添加对象追随器

语录: 我已经准备好了足够挡雨的伞,可是却迟迟没有等到雨的到来,这样的尴尬只是我漫长人生中的小插曲罢了。 前言: 对象追随器的目的是让一个或多个游戏对象跟随场景中的另一个对象,而无需将游戏对象嵌套在彼此之下。 …

『pyqt5 从0基础开始项目实战』13. 打包生成exe(保姆级图文)

目录 项目源码打包exe打开闪退需要db文件夹总结 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中 项目源码 请查阅专栏上文获取源码 ## 安装库包 python pip install pyinstaller ![…

Stable Diffusion的原理

CSDN-markdown语法之怎样使用LaTeX语法编写数学公式 参考视频:【diffusion】扩散模型详解!原理代码! 用一颗桃树为你讲清楚 知识点:AI绘图原理 Diffusion扩散模型 Windows深度学习环境搭建:Windows深度学习环境搭建 …

FFmpeg开发笔记(三)FFmpeg的可执行程序介绍

外界对于FFmpeg主要有两种使用途径,一种是在命令行运行FFmpeg的可执行程序,该方式适合没什么特殊要求的普通场景;另一种是通过代码调用FFmpeg的动态链接库,由于开发者可以在C代码中编排个性化的逻辑,因此该方式适合厂商…

一篇文章介绍分布式事务

1、事务的基本概念 事务 事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销。简单地说,事务提供一种“要么什么都不做,要么做全套”机制。 本地…

【越早知道越好】的道理——能够大大提升效率的【快捷键】

文章目录 1️⃣虚拟桌面第一步:打开任务视图第二步:创建桌面第三步:桌面切换第四步:桌面删除 2️⃣窗口切换3️⃣桌面分屏如何分屏 前言🧑‍🎤:作为程序员👨‍💻&#xf…