STL空间配置器框架分析

news2024/12/1 0:38:17

目录

一、空间配置器概念

二、空间配置器的作用

三、内存池技术

四、空间配置器的实现原理

3.1 流程概述

3.2 一级空间配置器

3.3 二级空间配置器

3.3.1 二级空间配置器设计

3.3.2 内存碎片问题


一、空间配置器概念

即为各个容器高效的管理空间(空间的申请与回收)的。虽然在常规使用STL时,可能用不到它,但站在学习研究的角度,学习它的实现原理对我们有很大的帮助。

二、空间配置器的作用

若实现各种STL容器时,所有需要空间的地方都使用new申请,虽然也可以完成基本的功能,但是会存在一些缺点:

1. 空间申请与释放需要使用者自行管理,容易造成内存泄漏

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

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

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

5. 申请空间失败时的应对方式不够合理

5. 代码结构比较混乱,代码复用率不高

6. 未考虑线程安全问题

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

三、内存池技术

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

四、空间配置器的实现原理

3.1 流程概述

使用空间配置器申请空间时,首先直接向二级空间配置器发起请求,请求的空间大于128byte则交由一级空间配置器处理,否则二级空间配置器进行处理。

一级空间配置器适合为容器申请较大的空间,如vector、unordered_map等连续空间的容器。

二级空间配置器适合频繁申请小块内存时使用,如list等容器。

3.2 一级空间配置器

一级空间配置器实现原理较为简单,本质上是直接对malloc与free进行了封装

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;
	}
	
	static void deallocate(void* p, size_t /* n */)// 对free的封装
	{
		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);
	}
};
template <int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n)// malloc申请空间失败时代用该函数
{
	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.3 二级空间配置器

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

3.3.1 二级空间配置器设计

当用户向二级空间配置器发送第一次申请前,二级空间配置器中并没有我们需要的空间。发出第一次申请后才会一次性申请一块足够大的内存空间(使用两个指针进行维护)。之后我们需要空间时,在这块空间切割即可。可以认为这两个指针维护的即为狭义的内存池。

static char *start_free;
static char *end_free;

但是释放空间的顺序不一定刚好与开辟空间的顺序相反,我们又没有记录每块切割的内存空间的位置,那该如何归还空间呢?

这时就需要用到哈希桶技术

但是并不需要128个桶来进行管理,而是选用1~128之间的所有8的倍数作为key,共有15个桶。

当需申请小块空间时,先将所需空间的大小向上对齐到8的倍数得到一个key,再在该key所对应的桶中查找是否存在内存块。有则将第一块返回给用户;没有则向桶中填充多块内存块(确保之后申请时有内存块),再将第一块返回给用户。

当狭义内存池中空间不足时,会malloc向堆区申请空间。若malloc失败(即已经没有空间),这时会向key值更大的桶中寻找是否有内存块(可能之前申请了)。若后面的桶中也没有可用的内存块,则会向一级空间配置器寻求帮助了。

为什么没有采用链表的方式对用户已经归还的空间进行管理?

使用链表的话,用户申请空间时在查找合适的小块内存时效率较低。采用哈希桶更加高效。

每个桶中的内存块是如何连接的呢?

当内存块不使用时,每个内存块前会使用一个指针大小的内存来存储下一个内存块的地址。采用联合体的方式实现。 

union obj {
        union obj * free_list_link;
        char client_data[1];    /* The client sees this.        */
  };

为什么key选用8的倍数?

在64位环境下指针的大小为8字节,保证最小的内存块都至少可以存下一个指针。(保证32位、64位系统都可以使用)

可能用户申请的空间并不是8的整数倍,切割的内存块大小会向上对齐到8的整数倍。比如:申请5字节空间,会切割8字节的空间。

注意:

一个进程中只会有一个空间配置器,进程中所有容器需要的空间都到对应空间配置器申请。进程终止,对应空间配置器释放。可以采用单例模式进行实现。

3.3.2 内存碎片问题

内存碎片问题大致可以分为内碎片和外碎片。

外碎片问题

内碎片问题

即实际分配内存数比需要的内存数多,导致空间浪费。二级配置器切割内存块向上对齐8的整数倍,就造成了内碎片问题。

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

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

相关文章

聊一聊双亲委派模式

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 说起双亲委派模型&#xff0c;不得不说一下类加载器。 类加载器是什么&#xff1f; 当我们编译Java类时&#xff0c;JVM会创建与平台和…

Allegro174版本新功能介绍之移动画布不闪屏设置

Allegro174版本新功能介绍之移动画布不闪屏设置 Allegro在升级到174版本后,在移动画布的时候,视图数据量比较大的情况,会出现闪屏现象 Allegro在切换到Open GL模式下,这个现象会有所缓解,具体操作如下 选择Setup选择User-preferences

【Ansible】ansible 基础知识

ansible 文章目录ansible一、ansible Ad-Hoc 命令1.命令格式2.模块类型3.联机帮助4.常用模块4.1 command & shell 模块4.2 script 模块4.3 copy 模块4.4 yum_repository4.5 yum 模块4.6 systemd 模块4.7 group 模块4.8 user 模块4.9 file 模块4.10 cron 模块4.11 template …

SIE高级副总裁:关于PS VR2定价、设计、内容的思考

2023年2月22日&#xff0c;索尼将正式推出次世代头显PS VR2&#xff0c;首发VR游戏将超过30款&#xff0c;其中包括热门游戏《GT赛车7 VR》。此外&#xff0c;PS5全球销量也已突破3000万。实际上距离索尼推出上一代PS VR&#xff0c;已经过去了6年时间&#xff0c;相比于Quest等…

M12269 支持PD3.1等快充协议、140W升降压3-8节多串锂电充放电移动电源管理IC

引言 在快充技术持续迭代升级的过程中&#xff0c;充电从小功率向中大功率的转变是最为明显的。支持的快充功率从最初的7.5W&#xff0c;已经向最高240W迈进。PD3.1协议的推出&#xff0c;进一步助力快充加速走向中大功率。新增三种固定电压档&#xff1a;28V&#xff08;100-1…

VS1053 MP3模块介绍

VS1053MP3模块简介ATK-VS1053 MP3 MODULE是ALIENTEK推出的一款高性能音频编解码模块&#xff0c;该模块采用VS1053B作为主芯片&#xff0c;支持&#xff1a;MP3/WMA/OGG/WAV/FLAC/MIDI/AAC等音频格式的解码&#xff0c;并支持&#xff1a;OGG/WAV音频格式的录音&#xff0c;支持…

Mask RCNN网络源码解读(Ⅱ) --- ResNet、ResNeXt网络结构、BN及迁移学习

目录 1.ResNet简介 2.residual结构和ResNet-34详解 2.1 residual结构 2.2 Batch Normalization 3.迁移学习 4.ResNeXt网络结构 1.ResNet简介 ResNet在2015年由微软实验室提出&#xff0c;斩获当年lmageNet竞赛中分类任务第一名&#xff0c;目标检测第一名。获得coco数据…

信道模型:Rayleigh、Rician、卫星→地面

这里写目录标题比较C. Loo模型&#xff1a;直射阴影&#xff0c;多径不阴影Corazza模型&#xff1a;直射和多径都阴影Lutz模型&#xff1a;好坏2个状态Rayleigh and Rician 信道生成Shadowed-Rician 直射径 散射径[Secure Transmission in Cognitive Satellite Terrestrial Net…

Redis的String类型,原来这么占内存

Redis的String类型&#xff0c;原来这么占内存 存一个 Long 类型这么占内存&#xff0c;Redis 的内存开销都花在哪儿了&#xff1f; 1、场景介绍 假设现在我们要开发一个图片存储系统&#xff0c;要求这个系统能够根据图片 ID 快速查找到图片存储对象 ID。图片 ID 和图片存储对…

【Flink基础】-- 源码中的注解

1.Flink自定义注解级别在升级 Flink版本至 1.15.3时&#xff0c;偶然遇到了一个异常&#xff0c;然后就准备详细了解下源码中的注解。设计注解的初衷&#xff1a;为了更好地进行代码和版本管理&#xff0c;Flink使用了Java的注解特性自定义了注解&#xff0c;对代码进行增强说明…

Kubernetes安全扫描之kubescape

一 背景 Kubescape 是第一个用于测试 Kubernetes 是否按照 NSA 和 CISA 的 Kubernetes 强化指南中定义的安全部署的工具 使用 Kubescape 测试集群或扫描单个 YAML 文件并将其集成到您的流程中。 二 特性 功能&#xff1a;提供多云 K8s 集群检测&#xff0c;包括风险分析、安…

stack 中缀表达式求值

【解法一】双栈思路梳理 【解法二】利用逆波兰表达式求解&#xff08;中缀转后缀&#xff09; 这个有俩种方法&#xff0c;一是直接根据条件进行各种情况的推导直接由中缀表达式求解&#xff0c; 二就是将中缀表达式转化为后缀表达式&#xff0c;利用更容易的逆波兰表达式求解…

分享微信小程序开发详细步骤

1、梳理小程序开发功能需求自己可以用思维导图写出自己想要开发的小程序里面&#xff0c;需要设置哪些功能&#xff0c;这些功能帮助我解决什么问题。然后把想法用文字形式在思维导图中写出来。如果不知道如果梳理&#xff0c;也可以找专业的产品经理协助处理。如果不知道功能可…

Vector - VT System - CANCANFDLIN板卡_VT6104|6204

对于做车载开发或者测试的朋友来说&#xff0c;大部分对于CANoe&#xff08;VN1600系列&#xff09;是相当的熟悉&#xff0c;我们知道CANoe支持CAN&CANFD&LIN&#xff0c;都有对应的硬件来匹配&#xff1b;但是如果需要做台架测试&#xff0c;VN1600系列的硬件放在架子…

读书笔记:来自一个外企优秀销售的业务心法和秘籍(中)

01 普通销售能达到的三种境界第一 投其所好 &#xff08;110&#xff09;销售把自己的资源1奉献出去&#xff0c;控制不了对方的回报&#xff0c;新人都处在这个阶段。第二 互利互惠 &#xff08;1&#xff0b;1&#xff1d;1&#xff09;大家互相贡献自己的一部分&#xff0c;…

满足你一切需求的 MMYOLO/MMDet 可视化 (一)

可视化在深度学习时代算是核心需求&#xff0c;借助可视化功能&#xff0c;研究者可以快速定位分析模型以及排查问题。在 OpenMMLab 2.0 时代&#xff0c;MMEngine 对常用的可视化需求进行了设计和实现&#xff0c;其具备如下功能&#xff1a; 提供丰富的开箱即用可视化功能&a…

TP6队列与延时队列

安装在此我就不再略过TP6的项目创建过程了&#xff0c;大致就是安装composer工具&#xff0c;安装成功以后&#xff0c;再使用composer去创建项目即可。think-queue 安装composer require topthink/think-queue项目中添加驱动配置我们需要在安装好的config下找到 queue.php<…

Solon v1.12.1 发布,已累计 10000+ 次提交

一个更现代感的 Java 应用开发框架&#xff1a;更快、更小、更自由。没有 Spring&#xff0c;没有 Servlet&#xff0c;没有 JavaEE&#xff1b;独立的轻量生态。主框架仅 0.1 MB。 Controller public class App {public static void main(String[] args) {Solon.start(App.cl…

leetcode刷题精讲————17.电话号码的字母组合

力扣https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/ 这道题要用到多叉树遍历、回溯、递归、排列组合等相关知识&#xff0c;算是比较经典的例题了&#xff0c;掌握它的核心思想就可以解决这一大类问题。 首先&#xff0c;2~9的数字对应不同…

JS 安全策略 101

依赖审计 依赖审计其实就是利用 npm 或是 yarn 自带的一个 audit 命令检测 node_module 里存在的一些具有安全隐患的依赖项。我习惯用yarn audit, 所以给大家放了张自己博客的 yarn 审计结果。这里显示&#xff1a;一个叫 trim 的包太老了&#xff0c;有很高的安全风险。 有风…