c++(空间配置器)[32]

空间配置器

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

一级空间配置器 || 二级空间配置器

在这里插入图片描述
默认先走二级然后判断

二级空间配置器

在这里插入图片描述
一个指针指向start_free然后start_free向后移动,相当于哈希桶的头删和头插
在这里插入图片描述
8byte:切大补小
C++的二级空间配置器按照8字节(或者更大的倍数)切分内存的原因有以下几点:

  1. 内存对齐:许多计算机体系结构要求数据在内存中的地址是对齐的,即数据的起始地址必须是某个特定值的倍数。按照8字节切分内存可以确保分配的内存块的起始地址满足对齐要求,从而提高内存访问的效率。

  2. 减少内存碎片:内存碎片是指分配的内存块之间存在的未使用的小块内存。通过按照8字节切分内存,可以减少内存碎片的产生。如果按照较小的单位(如1字节)切分内存,会导致更多的内存碎片,降低内存的利用率。

  3. 提高内存分配的效率:按照8字节切分内存可以提高内存分配的效率。二级空间配置器使用了一些数据结构(如自由链表)来管理内存池,按照固定大小的块进行切分可以简化数据结构的设计和操作,从而提高内存分配的速度。

需要注意的是,按照8字节切分内存并不是绝对的规定,具体的实现可能会根据不同的编译器、操作系统和硬件平台进行调整。但按照8字节切分内存是比较常见的做法,可以在大多数情况下获得较好的性能和内存利用率。

好的,我来具体解释一下被还回来的小空间是如何被申请的大空间利用的过程。以下是一个简化的示意图:

+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+
  1. 初始状态:大空间被划分为多个小空间,每个小空间的状态为已分配或未分配。
+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   | A |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+
  1. 释放小空间:当程序不再需要某个小空间时,将其释放回内存池。
+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+
  1. 标记小空间为可用:二级空间配置器会将被释放的小空间标记为可用。
+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+
  可用   可用   可用
  1. 分配大空间:当程序需要申请大空间时,二级空间配置器会查找可用的连续小空间。
+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   | A |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+
  1. 标记小空间为已分配:二级空间配置器会将被分配的小空间标记为已分配,并从内存池中移除。
+-----------------------+
|         大空间         |
+-----------------------+
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|   |   |   |   |   |   |
+-----------------------+

通过这个过程,被还回来的小空间可以被申请的大空间利用,从而实现内存的高效利用。

需要注意的是,实际的内存管理过程可能更加复杂,涉及到内存碎片的合并、内存池的扩展等操作。上述示意图仅用于说明基本的内存分配和释放过程。

不是所有进程都公用一个空间配置器。在操作系统中,每个进程都有自己独立的虚拟地址空间,这意味着每个进程都有自己的内存管理单元。

每个进程的内存管理单元负责管理该进程的内存分配和释放。这包括将进程所需的内存从操作系统中分配出来,并在进程不再需要时将其释放回操作系统。

因此,每个进程都有自己的空间配置器,用于管理其内存分配和释放。这样可以确保每个进程的内存操作互不干扰,提高了系统的安全性和稳定性。

需要注意的是,不同进程之间可以通过进程间通信的机制共享内存,但共享的内存通常是通过特殊的方式进行管理,而不是直接使用一个公用的空间配置器。

碎片(一部分一部分还)
空间配置器的碎片指的是内存中的小块未被使用的空间,这些空间可能散落在已分配的内存块之间,无法被有效利用。为了解决内存碎片的问题,空间配置器通常会采取合并碎片的策略。

具体来说,当一个内存块被释放回空间配置器时,空间配置器会尝试将其与相邻的空闲内存块进行合并,以形成更大的连续空闲内存块。这个过程称为内存碎片的合并。

合并碎片的策略可以有多种实现方式,以下是一种常见的策略:

  1. 首次适应(First Fit):空间配置器会从内存池中的第一个空闲内存块开始遍历,找到第一个足够大的空闲内存块来满足分配请求。如果找到了合适的内存块,就将其分割成两部分,一部分用于分配,另一部分保留为新的空闲内存块。

  2. 循环首次适应(Next Fit):类似于首次适应,但是从上一次分配的位置开始遍历内存池,直到找到合适的内存块。这样可以减少遍历的次数。

  3. 最佳适应(Best Fit):空间配置器会遍历整个内存池,找到能够满足分配请求并且大小最接近的空闲内存块。这样可以最大程度地减少内存碎片。

  4. 最坏适应(Worst Fit):空间配置器会遍历整个内存池,找到能够满足分配请求并且大小最大的空闲内存块。这样可以保留更多的小空闲块,但是可能会导致更多的内存碎片。

无论采用哪种策略,合并碎片的目的都是尽可能地利用内存,减少内存碎片的影响。通过合并碎片,空间配置器可以提供更大的连续内存块,从而满足大内存分配的需求。

在这里插入图片描述
解决外碎片问题的方法之一是使用内存池(Memory Pool)或内存池分配器(Memory Pool Allocator)。

内存池是一种预先分配一大块连续内存的数据结构,然后根据需要从该内存池中分配小块内存。内存池可以避免频繁向系统申请小块内存的开销,并且可以减少外碎片的产生。

以下是解决外碎片问题的一种基本思路:

  1. 在程序初始化阶段,分配一大块连续的内存作为内存池。

  2. 将内存池划分为固定大小的小块内存,可以使用链表或位图等数据结构来管理这些小块内存的分配情况。

  3. 当需要申请小块内存时,从内存池中找到一个空闲的小块内存进行分配。

  4. 当小块内存不再使用时,将其标记为空闲,并将其归还到内存池中。

通过使用内存池,可以避免频繁向系统申请小块内存,从而减少了内存碎片的产生。此外,内存池还可以提供连续的内存块,使得可以更容易地申请大块内存。

需要注意的是,使用内存池也会带来一些额外的开销,比如内存池的初始化和管理。因此,在选择是否使用内存池时,需要根据具体的应用场景和需求进行权衡。

STL六大组件

  1. 容器(Containers):STL提供了多种容器类,如vector、list、deque、set、map等。容器类提供了不同的数据结构,用于存储和管理数据。每种容器类都有自己的特点和适用场景,可以根据需要选择合适的容器类。

  2. 算法(Algorithms):STL提供了一组常用的算法,如排序、查找、合并、删除等。这些算法可以应用于各种容器类,提供了高效的实现和使用方式。使用STL算法可以简化编程过程,提高代码的可读性和可维护性。

  3. 迭代器(Iterators):STL提供了迭代器作为容器和算法之间的桥梁。迭代器提供了一种统一的访问容器元素的方式,可以通过迭代器遍历容器中的元素,实现对容器的操作。STL还提供了不同种类的迭代器,如输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器,每种迭代器都有不同的功能和限制。

  4. 仿函数(Functors):STL中的仿函数是一种可调用对象,类似于函数指针,可以在算法中使用。仿函数可以作为算法的参数,用于定义算法的行为。STL提供了一些内置的仿函数,如比较仿函数、数值仿函数等,同时也可以自定义仿函数。

  5. 适配器(Adapters):STL提供了适配器用于修改容器或者算法的接口。适配器可以将一种容器或算法的接口转换为另一种接口,使得它们可以互相兼容。STL中常见的适配器有迭代器适配器、函数适配器等。

  6. 分配器(Allocators):STL提供了分配器用于管理内存的分配和释放。分配器可以为容器提供自定义的内存管理策略,如内存池分配器、堆分配器等。通过分配器,可以控制容器的内存使用方式,提高内存的分配效率和性能。

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

复习

vector:基于动态数组
list:双向链表
set:平衡二叉搜索树(元素唯一)
map:红黑树
unordered_map:基于哈希表(Hash Table)
std::unordered_set:基于哈希表实现,它存储一组无序的唯一元素。std::unordered_set提供了快速的插入、删除和查找操作,平均情况下的时间复杂度为O(1)。

map和unorder_map,set和unorder_set的本质区别

std::mapstd::unordered_mapstd::setstd::unordered_set的本质区别在于它们使用的底层数据结构和提供的操作效率。

  1. std::mapstd::unordered_map的本质区别:
  • std::map基于红黑树实现,它保持了元素的有序性。红黑树是一种自平衡的二叉搜索树,提供了对键的快速查找、插入和删除操作,时间复杂度为O(log n)。std::map中的元素按照键的顺序进行排序,因此可以用作有序的查找表。
  • std::unordered_map基于哈希表实现,它使用键的哈希值来确定元素的存储位置。哈希表提供了快速的插入、删除和查找操作,平均情况下的时间复杂度为O(1)。std::unordered_map中的元素没有固定的顺序,因此不能用作有序的查找表,但它在大多数情况下提供了更快的操作。
  1. std::setstd::unordered_set的本质区别:
  • std::set基于红黑树实现,它存储一组有序的唯一元素。std::set提供了高效的插入、删除和查找操作,时间复杂度为O(log n)。
  • std::unordered_set基于哈希表实现,它存储一组无序的唯一元素。std::unordered_set提供了快速的插入、删除和查找操作,平均情况下的时间复杂度为O(1)。

因此,std::mapstd::set适用于需要有序元素或按照键进行排序的场景,而std::unordered_mapstd::unordered_set适用于对元素顺序没有要求,但需要更快的操作速度的场景。

在这里插入图片描述
在这里插入图片描述
multi版本:允许键值冗余

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全---正则回溯

目录 一、题目引入 二、举出回溯例子进行分析 第一步: 正则往前匹配 第二步:匹配到头 第三步:往回匹配 第四步:直到分号结束 (匹配上) 原因: 三、进入正题一(分析题型&#…

【JavaWeb】实训的长篇笔记(下)

文章目录 八、功能实现1、注册功能2、登录功能3、问题说明4、首页数据显示5、后台管理 八、功能实现 1、注册功能 jsp:能够在页面中把数据动态化,jsp和html在元素标签上是无区别的,区别是html中写上java代码就成了jsp文件。filename.jsp。 需…

【Megatron-DeepSpeed】张量并行工具代码mpu详解(四):张量并行版Embedding层及交叉熵的实现及测试

相关博客 【Megatron-DeepSpeed】张量并行工具代码mpu详解(四):张量并行版Embedding层及交叉熵的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(三):张量并行层的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(一)&#xff1a…

安装paddleSeq2.7.0版本模块-笔记

安装paddleSeq2.7.0版本模块-笔记 先安装conda和python版本 本机安装的conda 22.9.0 python2.9.12 paddle2.4.2 paddlepaddle-gpu2.4.2 cuda10.2 安装matplotlib3.5.0版本 opencv_python-4.5.4.60-cp39-cp39-win_amd64.whl 测试采用分割模型名称:BiSeNetv2 #BiSe…

Android 项目导入高德SDK初次上手

文章目录 一、前置知识:二、学习目标三、学习资料四、操作过程1、创建空项目2、高德 SDK 环境接入2.1 获取高德 key2.2下载 SDK 并导入2.2.1、下载SDK 文件2.2.2、SDK 导入项目2.2.3、清单文件配置2.2.4、隐私权限 3、显示地图 一、前置知识: 1、Java 基…

Server - 文字转语音 (Text to Speech) 的在线服务 TTSMaker

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132287193 TTSMaker 是一款免费的文本转语音工具,提供语音合成服务,支持多种语言,包括英语、法语、德语、西班…

每日一题——对称的二叉树

题目 给定一棵二叉树,判断其是否是自身的镜像(即:是否对称) 例如: 下面这棵二叉树是对称的 下面这棵二叉树不对称。 数据范围:节点数满足 0≤n≤1000,节点上的值满足 ∣val∣≤1000 要求&…

Rust 复数运算,重载加减乘除运算

复数 基本概念 复数定义 由实数部分和虚数部分所组成的数,形如a+bi 。 其中a、b为实数,i 为“虚数单位”,i 的平方等于-1。 a、b分别叫做复数a+bi的实部和虚部。 当b=0时,a&am…

Java8函数式编程

ISBN: 978-7-115-38488-1 作者:【英】Richard Warburton 页数:132页 阅读时间:2023-08-05 推荐指数:★★★★★ 练习项目:https://github.com/RichardWarburton/java-8-lambdas-exercises 虽然这本书出版于2014年&…

前端食堂技术周刊第 93 期:7 月登陆 Web 平台的新功能、Node.js 工具箱、Nuxt3 开发技巧、MF 重构方案

美味值:🌟🌟🌟🌟🌟 口味:橙橙冰萃美式 食堂技术周刊仓库地址:https://github.com/Geekhyt/weekly 大家好,我是童欧巴。欢迎来到前端食堂技术周刊,我们先来…

SQLyog中导入CSV文件入库到MySQL中

1.在数据库中新建一个表,设置列名(与待导入文件一致),字段可以多出几个都可以 2.右键表名,导入- - >导入使用本地加载的CSV数据 选择使用加载本地CVS数据 3.指定好转义字符,将终止设置为,号(英文状态下…

2023牛客暑期多校训练营9-Non-Puzzle: Segment Pair

2023牛客暑期多校训练营9-Non-Puzzle: Segment Pair https://ac.nowcoder.com/acm/contest/57363/I 文章目录 2023牛客暑期多校训练营9-Non-Puzzle: Segment Pair题目大意解题思路代码 题目大意 解题思路 对于每一对 [ l i , r i ] [l_i,r_i] [li​,ri​]和 [ l i ′ , r i …

cmake-ibmtpm1682编译

1、error Ossl library is using different radix 异常解决 RADIX_BITS由 64改成32 --whole-archive CMakeFiles\ibm-tpm-my.dir/objects.a -Wl, --no-whole-archive CMakeFiles\ibm-tpm-my.dir\linklibs.rsp CMake中的 --whole-archive以及–no-whole-archive两者都是编译器…

AppStream下载元数据失败

错误:为仓库 AppStream 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist 目录 一、域名解析 二、CentOS-AppStream.repo 三、CentOS-Base.repo 四、CentOS-Extras.repo 五、rpm更新 一、域名解析 先验证 ping www.baidu.com 不…

基于C#UI Automation自动化测试

步骤 UI Automation 只适用于,标准的win32和 WPF程序 需要添加对UIAutomationClient、 UIAutomationProvider、 UIAutomationTypes的引用 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.D…

【ARM 调试】如何从 crash 信息找出问题原因

一、问题背景 粉丝在进行 ARM-A 系列软件编程时遇到以下问题,串口打印这段日志后就重启了,粉丝求助问是什么原因? Unhandled Exception in EL3. x30 0x0000000000b99b84 x0 0x00000000179a25b0 x1 …

Prometheus技术文档-基本使用-配置文件全解!!!!!

简介: Prometheus是一个开源的系统监控和告警系统,由Google的BorgMon监控系统发展而来。它主要用于监控和度量各种时间序列数据,比如系统性能、网络延迟、应用程序错误等。Prometheus通过采集监控数据并存储在时间序列数据库中,…

【apifox】如何写一份合格的 API 文档?

要想弄清楚如何开始写出一份合格的 API 文档,我们需要首先了解什么是 API,它的使用场景有哪些,应该具备什么样的能力。 什么是 API? 想象一下,当小 A 购入了一台新的电脑后,希望将显示画面投射至一块色准…

对比学习论文综述总结

第一阶段:百花齐放(18-19中) 有InstDisc(Instance Discrimination)、CPC、CMC代表工作。在这个阶段方法模型都还没有统一,目标函数也没有统一,代理任务也没有统一,所以说是一个百花齐放的时代 1 判别式代理任务---个体判别任务 1.1 Inst Dict---一个编码器+一个memory…

Redis_主从复制

8. 主从复制 8.1 简介 主从库采用读写分离的方式 读操作:主库、从库都可以处理写操作:首先写到主库执行,然后再将主库同步给从库。 实现读写分离,性能扩展 容灾快速恢复 8.2 主从复制步骤 创建一个目录 ,在root下创建一个m…