STL源码分析之内存池

STL源码剖析 复盘STL-2 阅读详情
前言

上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析一下

内存池

static data template的初始化

template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::start_free = 0;	// 内存池的首地址
template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::end_free = 0;	// 内存池的结束地址
template <bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;	// 多次调用内存池, 就会更多的是给链表分配内存, 这就是一个增量.

这里代码注释写的很清楚了, 我就提取出来分析一下吧

  1. 内存池的大小大于需要的空间, 直接返回起始地址(nobjs默认设置为20, 所以每次调用都会给链表额外的19个内存块)
  2. 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就全部分配出去
  3. 如果一个对象的大小都已经提供不了了, 先将零碎的内存块给一个小内存的链表来保存, 然后就准备调用malloc申请40块+额外大小的内存块(额外内存块就由heap_size决定), 如果申请失败跳转到步骤4, 成功跳转到步骤6
  4. 充分利用更大内存的链表, 通过递归来调用他们的内存块
  5. 如果还是没有内存块, 直接调用一级配置器来申请内存, 还是失败就抛出异常, 成功申请就继续执行
  6. 重新修改内存起始地址和结束地址为当前申请的地址块, 重新调用chunk_alloc分配内存
// 内存池
template <bool threads, int inst>
char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
  	char * result;
  	size_t total_bytes = size * nobjs;            // 链表需要申请的内存大小
  	size_t bytes_left = end_free - start_free;    // 内存池里面总共还有多少内存空间

	  // 内存池的大小大于需要的空间, 直接返回起始地址
  	if (bytes_left >= total_bytes) 
  	{
	    result = start_free;
    	start_free += total_bytes;  // 内存池的首地址往后移
	    return(result);
  	}
  	// 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就按对齐方式全部分配出去
  	else if (bytes_left >= size) 
  	{
	    nobjs = bytes_left/size;
    	total_bytes = size * nobjs;
    	result = start_free;
    	start_free += total_bytes;  // 内存池的首地址往后移
    	return(result);
  	} 
  	else 
  	{ 
	    // 如果一个对象的大小都已经提供不了了, 那就准备调用malloc申请两倍+额外大小的内存
	    size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
    	// Try to make use of the left-over piece.
    	// 内存池还剩下的零头内存分给给其他能利用的链表, 也就是绝不浪费一点.
    	if (bytes_left > 0) 
    	{
      		// 链表指向申请内存的地址
      		obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left);
      		((obj *)start_free) -> free_list_link = *my_free_list;
      		*my_free_list = (obj *)start_free;
    	}
    	start_free = (char *)malloc(bytes_to_get);
    	// 内存不足了
    	if (0 == start_free) 
    	{
      		int i;
      		obj * __VOLATILE * my_free_list, *p;
      		// 充分利用剩余链表的内存, 通过递归来申请
      		for (i = size; i <= __MAX_BYTES; i += __ALIGN) 
      		{	
	        	my_free_list = free_list + FREELIST_INDEX(i);
	        	p = *my_free_list;
	        	if (0 != p) 
	            {
	          		*my_free_list = p -> free_list_link;
          			start_free = (char *)p;
	          		end_free = start_free + i;
          			return(chunk_alloc(size, nobjs));
    	    	}
      		}
      		// 如果一点内存都没有了的话, 就只有调用一级配置器来申请内存了, 并且用户没有设置处理例程就抛出异常
      		end_free = 0;	// In case of exception.
      		start_free = (char *)malloc_alloc::allocate(bytes_to_get);
	    }
	    	// 申请内存成功后重新修改内存起始地址和结束地址, 重新调用chunk_alloc分配内存
	    	heap_size += bytes_to_get;
	    	end_free = start_free + bytes_to_get;
    		return(chunk_alloc(size, nobjs));
  	}	
}

chunk_alloc函数的第34行FREELIST_INDEX的实现, 他将传入的bytes执行+7除8操作, 实现将byte调为大于byte最近8的整数.

    static  size_t FREELIST_INDEX(size_t bytes) {
      return (((bytes) + __ALIGN-1)/__ALIGN - 1);
    }

这种方法很像c程序字节的对齐, 就像下面这样, 从而实现字节的对齐

#define MASK 0xffffffff
static  size_t FREELIST_INDEX(size_t bytes) {
      return (((bytes) + __ALIGN-1)/MASK);
    }

总结

内存池的存在就是为了能快速的提供我们做需要的内存并且保存多余的空间, 让STL分配空间不再每次都进行malloc和free的操作, 效率又很有保障. 有时用户申请的块更小, 我们也能充分的利用起来. 唯一可能不足的是我们每次只申请char个大小, 但是内存池获得的确是8字节的大小. 感谢@Hall_Wood指出8字节对齐计算的问题.

EMC系列EtherCAT总线运动控制器(二):Motion通讯连接、总线配置及诊断 雷赛-EMC系列EtherCAT总线运动控制器(二):Motion通讯连接、总线配置及诊断 阅读详情

相关推荐

Obsidian和Typora图片路径同步终极指南:告别混乱的assets文件夹

本文详细解析了Obsidian与Typora图片路径同步的终极解决方案,通过Custom Attachment Location插件实现动态路径管理,解决了两款工具间图片兼容性问题。文章提供了从基础配置到高级应用的完整指南,帮助用户告别混乱的assets文件夹,提升工作效率。

g9h0i1的博客 821

《STL源码剖析》学习笔记——空间配置

相信大多数人应该和我一样,对STL的认识是从使用它开始的。但是,这等利器都是双刃剑,不明原理地使用,往往会适得其反。举个例子来说,对vector进行增添或者删除之后,出于内存安全的考虑,原有的迭代器应该摒弃不用。或许,只有真正走进STL的源码,才能解答这些疑问。 《STL源码剖析》这本书的源码来自大名鼎鼎的SGI STL,它是相对来说可读性最高的一个版本。 从实现的角度来看,空间配置器是一切的基

relic911的专栏 451

matlab kwave模拟超声换能器学习笔记

kwave模拟超声换能器的学习笔记,从零开始造车轮

SolvingMaster的博客 3197

STL源码剖析(五)

一个万用的Hash Function 一般在产生对象的hash码时,许多人会将对象中各个类型的元素取得hash码后相加得出该元素的hash码。这样做除了简单没有任何依据,根据实际中的应用,会发现这种方法产生相同的hash码可能性很大。所以C++提出了一种产生hash码的方法。 class CustomerHash{ public: std::size_t operator()(c...

weixin_38170065的博客 218

[SystemC]SystemC中的模块和程序

SystemC 中的层次结构是使用类 sc_module 创建的。sc_module 可以直接使用,也可以使用宏 SC_MODULE “隐藏”。上面的示例 SC_MODULE 创建了一个名为 nand2 的 sc_module 类对象。它的输出纯粹是输入值的函数。因此,模型可以使用最简单的 SystemC 进程,即 SC_METHOD。摘要:本节包含一个完整的简单设计,用于演示 SystemC 中模块和流程的使用。同样,重要的是要注意这不是典型的设计风格 - 但它很好而且易于理解。为什么要看模块和流程?

元直的博客 1867

光学测量仿真软件:OpticsBuilder_(9).热应力分析与补偿

在OpticsBuilder中,定义材料的热膨胀系数可以通过API进行。以下是一个Python代码示例,展示如何在OpticsBuilder中定义材料的热膨胀系数。

kkchenjj的博客 1085

侯捷——STL源码剖析 笔记

通过面向对象高级编程(上)的学习,我们可以将malloc分配出的内存区块分为这几个部分。functor为算法服务,当算法需要一些额外准则时,我们使用仿函数来辅助实现算法。适配器在STL组件的灵活组合运用功能上,扮演着轴承、转换器的角色STL所提供的各种适配器中:1)改变仿函数接口者,称为函数适配器;2)改变容器接口者,称为容器适配器;3)改变迭代器接口者,称为迭代器适配器对于函数适配器,适配器他也需要获得对应的仿函数一些信息。tuple是C++11新标准里的类型。

木牛的博客 849

【机器学习-09】特征工程

特征工程是机器学习模型构建的初步工作,但它的重要性却贯穿整个模型生命周期。在进行特征工程时,我们需要充分利用数据科学的知识和技巧,结合具体的应用场景和业务需求,来制定出最合适的特征提取和转换策略。只有这样,我们才能为机器学习模型提供最有价值的输入,从而使其发挥出最大的潜力。总之,特征工程是机器学习中的一项关键任务,它需要我们用心去探索、去实践、去创新。只有不断地优化和完善特征工程的过程,我们才能构建出更加准确、更加可靠的机器学习模型,为实际应用带来更大的价值。

qq_38614074的博客 2万+

STL的内存池的设计源码分析和体会

STL的内存池的设计源码分析和体会

C++编程的专栏 1421

OpenHarmony深度定制:从系统到模块的全景剖析与自定义模块实战

目标:在中新增一个算法库,让产品可直接调用。关闭不用的 20+ 系统部件,ROM 缩小 50 %;为自家芯片新增专用驱动模块,快速点亮开发板;内将核心算法库以部件形式集成,实现商业闭源。万物互联时代,差异化才是护城河。

m0_67505153的博客 1031

CTR-GCN 论文解读

提出了一种信道拓扑优化图卷积,该卷积可以动态有效地对信道拓扑进行建模。共享拓扑是一个参数化的邻接矩阵,作为所有通道的拓扑先验,并提供顶点之间的一般相关性。通过使用特定于通道的相关性细化共享拓扑,CTR-GC 获得了通道拓扑。

一杯水果茶!足矣~ 3088

GNU STL源码分析(一) -- 空间配置器

一、allocator介绍和环境准备 allocator是所有STL库容器背后的空间配置器,各种STL容器都需要空间配置器用于给自身配置内存。在STL库的实现角度而言,最先应该被实现的就是空间分配器。 GNU或者GNUC++的编码习惯(也可以称为规则): 在函数名、类名或者宏名的最前面是两个下划线,就代表这是GNU内建的,是非C/C++标准的; 缩进经常以一个空格完成,对于适应Tab键缩进的我们看STL源码时不是很习惯和方便,同时函数返回值单独占一行。 使用的环境介绍:操作系统环境为Ubuntu2

weixin_51615179的博客 593

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SGI STL二级空间配置器源码剖析(1)

之前大概写过SGI STL相关的东西,讲了讲空间配置器的原理,这一系列就剖析一下源码。在C++STL里空间配置器做的事情就是分离了对象内存的开辟,释放,对象构造,析构我们看SGI STL的实现还是找到vector看他push_back实现会发现他的构造析构都是定义的全局的函数模板SGI STL两个allocator的实现还是一级的是malloc和free,和C++STL基本无差,不过二级的用内存池的方式实现就复杂了进到空间配置器源码看看。

oorik的博客 597

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STL源码分析之第二级配置器

前言 第一级是直接调用malloc分配空间, 调用free释放空间, 第二级三就是建立一个内存池, 小于128字节的申请都直接在内存池申请, 不直接调用malloc和free. 本节分析第二级空间配置器, STL将第二级配置器设置为默认的配置器, 所以只要一次申请的空间不超过128字节就默认在内存池中申请空间, 超过才会调用第一级配置器. 第二级配置器 首先先来介绍3个常量. __ALIGN ...

啦啦啦 822

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

STL源码分析之空间配置器

初次接触空间配置器 前言 SGI STL将new的申请空间和调用构造函数的两个功能分开实现, 如果对new不太清楚的, 可以先去看看这一篇new实现再来看配置器也不迟. 本节是STL分析的第一篇, 主要分析STL各个部分都会出现的alloc实现, 虽然每个部分都只会默认调用它, 不了解它也可以看懂分析, 但是他又是不可缺少的, 我们就以它做为开篇进行分析. &quot;new&quot;的实现 这里直接我们直接来看...

啦啦啦 1245

剖析 stl + glibc “内存泄漏” 原因

最近项目增加了一个模块,在 Centos 系统压测,进程一直不释放内存。因为新增代码量不多,经过排查,发现 stl + glibc 这个经典组合竟然有问题,见鬼了! 通过调试(Centos 调试 glibc 视频)和查阅 glibc 源码,好不容易才搞明白它 “泄漏” 的原因。 问题在于:ptmalloc2 内存池的 fast bins 快速缓存和 top chunk 内存返还系统的特点导致。 ???? 文章来源:剖析 stl + glibc “内存泄漏” 原因 1. 现象 上测试源码看看: /*

wenfh2020的专栏 1630

SGI STL的二级空间配置器的源码剖析并内存池的实现源码剖析

2019年8月16日23:41:07 剖析源码的好处:学习优秀的编程规范 和 设计理念;以及剖析源码的能力。 内存池的实现 内容如下: SGI STL二级空间配置器源码 Nginx内存池源码剖析 这两种内存池的实现和应用场景都是不一样的。 为什么要内存池呢? 答:C语言的库函数malloc和free C++的new和delete(其底层的内存管理上依旧是malloc和free)。但是在应用场...

孤傲小二~阿沐的博客 800

STL 内存池源码学习与思考

首先说明一下,这次学习的是STL空间配置器的源码中内存池部分的函数,下面是源码:template char* __default_alloc_template::_S_chunk_alloc(size_t __size, int& __nobjs) { char* _

tongjunyu66的博客 343

【STL】实现简单的空间配置器

1、模拟实现STL源码中实现的空间配置器 实现方式: STL源码中的空间配置器的实现分为一级与二级空间配置器; 1.1 一级空间配置器

晓东的博客 641

配接器(包括仿函数),萃取器、分配器、迭代器

今天重读《STL源码分析》,一目十行,看的很爽,想起当年看这本书,看着脑袋就大。说明这些年,功力还是有所增长的。 STL的精髓,总结起来,就四点:配接器(包括仿函数),萃取器、分配器、迭代器。其中分配器和迭代器是常人能想出的产物,萃取器是高手想出的产物,配接器是大师想出的产物。 分配器需要记住的是,一般的内存分配器没有启用次级分配能力,只启用了一级分配器,即直接使用malloc和free来

happylife1527的专栏 3028

STL-内存池

无

qq_55439426的博客 1754

STL源码分析目录

SIG STL源码分析 前言 本专栏主要以STL源码剖析分析路线来分析SIGSTL3.0源码. 整个模块准备对学习STL源码剖析之后做一个系统的总结, 这些都是我个人的理解, 如果分析有什么问题欢迎各位大佬们指出. 也很感谢作者以及网络中各个大佬的总结, 让我也能更容易更深刻的理解到STL强大和方便, 也让我对template感受深刻. 以下是我自己对STL版块进行分析. 总共分为六个版块 : 空...

啦啦啦 3637

内存池——nginx内存池跟stl内存池对比

内存池——nginx内存池跟stl内存池对比

John_ToStr的博客 415
上一篇: STL源码分析之第二级配置器
下一篇: STL源码分析之迭代器
Function_18
博客等级 码龄10年 193粉丝 239原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值