当前位置: 首页 > news >正文

C++空间配置器

目录

1.什么是空间配置器

2.为什么需要空间配置器

3.SGI-STL空间配置器实现原理

3.1一级空间配置器

3.2二级空间配置器

3.2.1内存池

3.2.2 SGI-STL中二级空间配置器设计

3.3 空间配置器的默认选择

4.空间配置器与容器的结合


1.什么是空间配置器

空间配置器,顾名思义就是为各个容器高效的管理空间(空间的申请与回收)的配置器,在默默地工作。下图是空间配置器、malloc的关系图:

空间配置器相当于是小灶,malloc是大食堂。空间配置器会为各个容器管理内存空间,即各个容器不需要去malloc那里拿内存空间。

2. 为什么需要空间配置器

在前面的博文中,我写了vector、list等等的容器的实现,在需要空间的地方都是通过new申请的,虽然在代码完成之后,代码可以正常运行,但是对于其中的内存空间,有以下不足:

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

 

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

 

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

 

④直接使用malloc与new进行申请,每块空间前有额外空间浪费。

 

⑤申请空间失败怎么应对。

  

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

 

⑦未考虑线程安全问题。

对于这些问题,C++为容器设计了一块高效的内存管理机制----空间配置器。

3.SGI-STL空间配置器的实现原理

以上提到的几点不足之处,最主要还是:频繁向系统申请小块内存造成的。那什么才算是小块内
存?SGI-STL以128字节作为小块内存与大块内存的分界线,将空间配置器其分为两级结构,一级空间配置器处理大块内存,二级空间配置器处理小块内存。即申请的空间大小大于128字节,那么就使用一级空间配置器,小于等于128字节就使用二级空间配置器。

 3.1一级空间配置器

一级空间配置器原理非常简单,直接对malloc与free进行了封装,并增加了C++中set_new_handle思想。一级空间配置器在申请空间的时候,如果失败了会直接抛异常。

template <int inst>
class __malloc_alloc_template
{
private:static void* oom_malloc(size_t);
public:// 对malloc的封装static void* allocate(size_t n){// 申请空间成功,直接返回,失败交由oom_malloc处理void* result = malloc(n); if (0 == result)result = oom_malloc(n);return result;}// 对free的封装static void deallocate(void* p, size_t /* n */){free(p);}// 模拟set_new_handle// 该函数的参数为函数指针,返回值类型也为函数指针// void (* set_malloc_handler( void (*f)() ) )()static void (*set_malloc_handler(void (*f)()))(){void (*old)() = __malloc_alloc_oom_handler;__malloc_alloc_oom_handler = f;return(old);}
};
// malloc申请空间失败时代用该函数
template <int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n)
{void (*my_malloc_handler)();void* result;for (;;){// 检测用户是否设置空间不足应对措施,如果没有设置,抛异常,模式new的方式my_malloc_handler = __malloc_alloc_oom_handler;if (0 == my_malloc_handler){__THROW_BAD_ALLOC;}// 如果设置,执行用户提供的空间不足应对措施(*my_malloc_handler)();// 继续申请空间,可能就会申请成功result = malloc(n);if (result)return(result);}
}
typedef __malloc_alloc_template<0> malloc_alloc;

3.2 二级空间配置器

二级空间配置器专门负责处理小于128字节的小块内存。如何才能提升小块内存的申请与释放的方式呢?SGI-STL采用了内存池的技术来提高申请空间的速度以及减少额外空间的浪费,采用哈希桶的方式来提高用户获取空间的速度与高效管理。

3.2.1内存池

内存池就是:先申请一块比较大的内存块已做备用,当需要内存时,直接到内存池中去去,当池中空间不够时,再向内存中去取,当用户不用时,直接还回内存池即可。避免了频繁向系统申请小块内存所造成的效率低、内存碎片以及额外浪费的问题。

在源码中,是由两个指针指向一块空间,这块空间便是内存池,它是二级配置器向malloc申请出来的。

3.2.2 SGI-STL中二级空间配置器设计

SGI-STL中的二级空间配置器使用了内存池技术,并且为了更方便更好的管理内存,二级空间配置器采用了哈希桶的方式。具体流程是这样的:

当需要申请128字节以内的内存的时候,二级空间配置器就会从内存池中拿到若干块内存,这个内存的大小为8的整数倍。然后分配给需要的地方,当使用完后,归还内存并不是直接归还到内存池中,而是使用哈希桶将内存块链接起来,方便后续的使用!

举个例子:我申请12字节大小的空间若干个,那么二级配置器就会从哈希桶中拿过来,但是如果此时的哈希桶是空的,那么就会去内存池中申请,如果内存池也是空的,内存池会去malloc申请一大块,然后内存池截取诺干个16个字节的内存块分配给用户,剩下的若干个链接到哈希桶中,因为内存池一般会截取几个内存块出来。

然后当用户使用完后,就会将这些内存块重新链接到哈希桶中。

那么为什么内存块都是8的整数倍呢?

当内存池已经空了,但是我需要申请一块空间,大小为16字节的。但是在哈希桶中,没有16字节的内存块,但是内存池已经空了,此时二级空间配置器不会放弃任何给你内存的希望,它会从后面的空闲着的内存块截取16字节拿过来!然剩下的字节的内存块也会被链接到前面对应字节数的桶中。

比如我需要16字节,但是发现哈希桶里没有,于是我拿24字节的,截取了16字节,还剩下8字节,这八字节就会被链接在8字节的桶中!这就是为什么要8的整数倍,因为可以在内存池空了的情况下,通过截取更大字节的内存块来分配给需要较小字节内存块的用户,然后可以将剩下的字节内存块链接去更小的桶中。

3.3 空间配置器的默认选择

GI-STL默认使用一级还是二级空间配置器,通过USE_MALLOC宏进行控制:

#ifdef __USE_MALLOC
typedef malloc_alloc alloc;
typedef malloc_alloc single_client_alloc;
#else// 二级空间配置器定义
#endif

在SGI_STL中该宏没有定义,因此:默认情况下SGI_STL使用二级空间配置器

4.与容器结合

使用list作为例子,看下面代码:

//typedef __default_alloc_template<__NODE_ALLOCTOR_THREADS, 0> alloc;
template < class T, class Alloc = alloc >
class list
{// ...// 实例化空间配置器typedef simple_alloc<list_node, Alloc> list_node_allocator;// ...
protected:link_type get_node(){// 调用空间配置器接口先申请节点的空间return list_node_allocator::allocate();}// 将节点归还给空间配置器void put_node(link_type p){list_node_allocator::deallocate(p);}// 创建节点:1. 申请空间 2. 完成节点构造link_type create_node(const T& x){link_type p = get_node();construct(&p->data, x);return p;}// 销毁节点: 1. 调用析构函数清理节点中资源 2. 将节点空间归还给空间配置器void destroy_node(link_type p){destroy(&p->data);put_node(p);}// ...iterator insert(iterator position, const T& x){link_type tmp = create_node(x);tmp->next = position.node;tmp->prev = position.node->prev;(link_type(position.node->prev))->next = tmp;position.node->prev = tmp;return tmp;}iterator erase(iterator position){link_type next_node = link_type(position.node->next);link_type prev_node = link_type(position.node->prev);prev_node->next = next_node;next_node->prev = prev_node;destroy_node(position.node);return iterator(next_node);}// ...
};

相关文章:

C++空间配置器

目录 1.什么是空间配置器 2.为什么需要空间配置器 3.SGI-STL空间配置器实现原理 3.1一级空间配置器 3.2二级空间配置器 3.2.1内存池 3.2.2 SGI-STL中二级空间配置器设计 3.3 空间配置器的默认选择 4.空间配置器与容器的结合 1.什么是空间配置器 空间配置器&#xff0…...

JConsole使用教程

JConsole是一个Java虚拟机的监控和管理工具&#xff0c;可以监控Java应用程序的内存使用、线程和类信息等。 以下是JConsole的使用教程&#xff1a; 1.启动JConsole JConsole是一个Java自带的工具&#xff0c;可以在bin目录下找到jconsole.exe文件。双击运行该文件即可启动JC…...

JS手写防抖和节流函数(超详细版整理)

1、什么是防抖和节流防抖&#xff08;debounce&#xff09;&#xff1a;每次触发定时器后&#xff0c;取消上一个定时器&#xff0c;然后重新触发定时器。防抖一般用于用户未知行为的优化&#xff0c;比如搜索框输入弹窗提示&#xff0c;因为用户接下来要输入的内容都是未知的&…...

我的Macbook pro使用体验

刚拿到Mac那一刻&#xff0c;第一眼很惊艳&#xff0c;不经眼前一亮&#xff0c;心想&#xff1a;这是一件艺术品&#xff0c;太好看了吧 而后再体验全新的Macos 系统&#xff0c;身为多年的win用户说实话一时间还是难以接受 1.从未见过的访达&#xff0c;不习惯的右键 2. …...

炼石入选“首届工业和信息化领域商用密码应用峰会”典型方案

2023年3月22日-23日&#xff0c;浙江省经济和信息化厅、浙江省通信管理局、浙江省密码管理局、工业和信息化部商用密码应用产业促进联盟联合举办的“首届工业和信息化领域商用密码应用峰会”&#xff08;以下简称峰会&#xff09;在浙江杭州成功举办&#xff0c;旨在深入推进工…...

使用new bing chat成功了

步骤一:在扩展商店搜索并安装modheader 打开浏览器; 点击右上角的三个点图标,选择“更多工具” -> “扩展程序”; 在扩展程序页面上方的搜索框中输入“modheader”,然后点击“搜索商店”; 在搜索结果中找到“ModHeader”扩展程序,点击“添加至”按钮,然后再点击“添…...

Golang每日一练(leetDay0019)

目录 55. 跳跃游戏 Jump Game &#x1f31f;&#x1f31f; 56. 合并区间 Mmerge Intervals &#x1f31f;&#x1f31f; 57. 插入区间 Insert Interval &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练…...

记录一次性能测试遇到的问题

零、压测指标问题 压测指标&#xff0c;一定要需求方定 啊&#xff0c;谁提压测需求&#xff0c;谁来定压测指标。 如果需求方&#xff0c;对压测指标没有概念&#xff0c;研发和测试&#xff0c;可以把历史压测指标、生产数据导出来给需求方看&#xff0c;引导他们来定指标&…...

C++运算符重载基础教程

所谓重载&#xff0c;就是赋予新的含义。函数重载&#xff08;Function Overloading&#xff09;可以让一个函数名有多种功能&#xff0c;在不同情况下进行不同的操作。运算符重载&#xff08;Operator Overloading&#xff09;也是一个道理&#xff0c;同一个运算符可以有不同…...

Git命令总结

全局配置 git config --global user.name ‘你的名字’ git config --global user.email ‘你的邮箱’ 当前仓库配置 git config --local user.name ‘你的名字’ git config --local user.email ‘你的邮箱’ 查看 global 配置 git config --global --list 查看当前仓库…...

【车载以太网】BCM89572A0BCFBG、BCM89559GB0BCFBG、BCM89559GA0BCFBG具有安全启动和安全通信功能

BCM89572A0BCFBG 设备是Broadcom第六代完全集成的L2多层开关解决方案&#xff0c;支持车载网络应用的汽车认证(AEC-Q100)和温度等级。BCM8956X系列产品为汽车行业提高了具有多种一流功能的交换机的标准&#xff0c;例如802.1AE MACsec等集成安全功能&#xff0c;增加了主机连接…...

Lighttpd入门教程

Lighttpd入门教程概述入门教程安装配置静态文件服务动态文件服务虚拟主机SSL启动服务器日志模块总结lighthttpd使用场景和原理使用场景原理概述 Lighttpd&#xff08;也称为轻量级HTTP服务器&#xff09;是一款快速、灵活、轻量级的Web服务器&#xff0c;旨在提供高性能和低资…...

Springboot 多线程分批切割处理 大数据量List集合 ,实用示例

前言 哲学提问镇贴&#xff1a; 不了解异步怎么使用的看官&#xff0c; 可阅&#xff1a; SpringBoot 最简单的使用异步线程案例 Async_小目标青年的博客-CSDN博客 Springboot Async异步扩展使用 结合 CompletableFuture_小目标青年的博客-CSDN博客 想了解更多关于批量list处…...

SQLMAP工具基础使用

本文用的是kali自带的sqlmap工具 我们通过常用命令来理解sqlmap的基本使用 目录 检测注入 获取敏感信息 获取表 获取表的字段 获取数据 --technique 使用指定的注入方式 使用基于时间的延时注入 支持多种注入检测 默认是全部 注入时使用随机的 HTTP User-Agent 设置超时时间 读…...

初学多线程爬虫

多线程在爬虫中应用非常广泛&#xff0c;对于中大型项目来说很有必要&#xff0c;今天我将以初学者的姿态来完成一个简单的多线程爬虫程序。 1、如何认识多线程 计算机完成一项或多项任务&#xff0c;往往可以存在很高的并行度&#xff1a;若是多核处理器则天然的可以同时处理…...

python-实验报告-3

1、编写程序&#xff0c;用户输入一个五位整数&#xff0c;输出其千位和十位数字之和。 num int(input()) # 12345 s1 (num//1000)%10 s2 (num//10)%10sum s1 s2 print(sum)心得&#xff1a; 首先&#xff0c;程序通过 input() 函数获取用户输入的整数&#xff0c;保存在…...

00_托管网站在Tor网络上_Ubuntu主机

title: 托管网站在Tor网络上 urlname: 00_托管网站在Tor网络上_Ubuntu主机 date: 2017-04-24 03:03:03 tags: 小技巧 categories: [小技巧] 托管网站在Tor网络上&#xff08;Ubuntu主机&#xff09;https://www.t00ls.net/thread-44040-1-1.html 大部分人接触Tor网络是由Tor …...

个人练习-Leetcode-659. Split Array into Consecutive Subsequences

题目链接&#xff1a;https://leetcode.cn/problems/split-array-into-consecutive-subsequences/ 题目大意&#xff1a;给出一个非递减数列nums[]&#xff0c;判断其是否能被分割成若干个满足以下条件的子列&#xff1a; 长度大于等于3元素严格递增且只相差1 子列的含义是&…...

OTA升级差分包签名

制作差分包时添加-k <key_path>参数 ./build/tools/releasetools/ota_from_target_files -k <key_path> -i old.zip new.zip update.zip<key_path>如何取值&#xff1f;查看ProjectConfig.mk 如果MTK_SIGNATURE_CUSTOMIZATIONyes并且MTK_INTERNALno&#xf…...

使用Buildroot制作根文件系统

寒暄几句 学习了uboot、内核、busybox根文件系统&#xff0c;想着做一个音频播放器。最后发现好像busybox好像没有带aplay架构&#xff0c;这就很麻烦需要自己移植。为了简便我就找大佬沟通了一下&#xff0c;大佬推荐了Buildroot工具来制作根文件系统。 平台 开发板&#x…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...