003 高并发内存池_整体框架设计

​🌈个人主页:Fan_558
🔥 系列专栏:高并发内存池
🌹关注我💪🏻带你学更多知识

文章目录

  • 前言
    • 一、ThreadCache整体框架设计
    • 二、CentralCache整体框架设计
    • 三、PageCache整体框架设计
  • 小结

前言

在本文中,重点是向你介绍ThreadCache、CentralCache、PageCache三个结构是怎样设计的
这三个结构对于我们代码的撰写至关重要

一、ThreadCache整体框架设计

线程缓存结构主要是解决锁竞争的问题,只要当前threadcache有空间,就不会跟其它线程竞争锁,线程缓存是每一个线程独享的结构,线程申请和释放内存都在这个缓存中进行,只能用于小于256KB的内存分配.整个线程缓存结构是不用加锁的。
定长内存池只支持固定大小内存块的申请释放,因此定长内存池中只需要一个自由链表管理释放回来的内存块。现在我们要支持申请和释放不同大小的内存块,那么我们就需要多个自由链表来管理释放回来的内存块,因此threadcache实际上一个哈希桶结构,每个桶中存放的都是一个自由链表。
在这里插入图片描述

threadcache支持小于等于256KB内存的申请,如果我们将每种字节数的内存块都用一个自由链表进行管理的话,那么此时我们就需要20多万个自由链表,光是存储这些自由链表的头指针就需要消耗大量内存,这显然是得不偿失的。
 这时我们可以选择做一些平衡的牺牲,让这些字节数按照某种规则进行对齐,例如我们让这些字节数都按照8字节进行向上对齐,那么threadcache的结构就是下面这样的,此时当线程申请1-8字节的内存时会直接给出8字节,而当线程申请9~16字节的内存时会直接给出16字节,以此类推
申请内存:

1、当内存申请size<=256KB,先获取到线程本地存储的thread cache对象,计算size映射的哈希桶自 由链表下标i。
2、如果自由链表_freeLists[i]中有对象,则直接Pop一个内存对象返回。
3、如果_freeLists[i]中没有对象时,则批量从central cache中获取一定数量的对象,插入到自由链表 并返回一个对象。

释放内存:

1、当释放内存小于256k时将内存释放回thread cache,计算size映射自由链表桶位置i,将对象Push到_freeLists[i]。
2、当链表的长度过长,则回收一部分内存对象到central cache。

二、CentralCache整体框架设计

当线程申请某一大小的内存时,如果threadcache中对应的自由链表不为空,那么直接取出一个内存块进行返回即可,但如果此时该自由链表为空,那么这时threadcache就需要向central cache申请内存了。
central cache的结构与threadcache是一样的,它们都是哈希桶的结构,并且它们遵循的对齐映射规则都是一样的,八字节为一个桶,不同的是,在CentralCache中,比如8Byte这个桶中装的是一个个Span,每个span管理的都是一个以页为单位的大块内存,每个桶里面的若干span是按照双链表的形式链接起来的,并且每个span里面还有一个自由链表,这个自由链表里面挂的就是一个个切好了的内存块,根据其所在的哈希桶这些内存块被切成了对应的大小。这样做的好处就是,当threadcache的某个桶中没有内存了,就可以直接到central cache中对应的哈希桶里去取内存就行了。

在这里插入图片描述
申请内存:

1、当thread cache中没有内存时,就会批量向central cache申请一些内存对象,这里的批量获取对象的数量使用了类似网络tcp协议拥塞控制的慢开始算法;central cache也有一个哈希映射的
2、spanlist,spanlist中挂着span,从span中取出对象给thread cache,这个过程是需要加锁的,不过这里使用的是一个桶锁,尽可能提高效率。 central cache映射的spanlist中所有span的都没有内存以后,则需要向pagecache申请一个新的 span对象,拿到span以后将span管理的内存按大小切好作为自由链表链接到一起。然后从span中取对象给thread cache。
3、centralcache的中挂的span中use_count记录分配了多少个对象出去,分配一个对象给thread cache,就++use_count

释放内存:

1、当thread_cache过长或者线程销毁,则会将内存释放回central cache中的,释放回来时-use_count。当use_count减到0时则表示所有对象都回到了span,则将span释放回page cache,pagecache中会对前后相邻的空闲页进行合并。

三、PageCache整体框架设计

页缓存是在central cache缓存上面的一层缓存,存储的内存是以页为单位存储及分配的,centralcache没有内存对象时,从page cache分配出一定数量的page,并切割成定长大小的小块内存,分配给centralcache。central cache的映射规则与thread cache保持一致,而page cache的映射规则与它们都不相同。pagecache的哈希桶映射规则采用的是直接定址法,比如1号桶挂的都是1页的span,2号桶挂的都是2页的span,以此类推

在这里插入图片描述

至于page cache当中究竟有多少个桶,这就要看你最大想挂几页的span了,这里我们就最大挂128页的span,为了让桶号与页号对应起来,我们可以将第0号桶空出来不用,因此我们需要将哈希桶的个数设置为129。

为什么这里最大挂128页的span呢?因为线程申请单个对象最大是256KB,而128页可以被切成4个256KB的对象,因此是足够的。当然,如果你想在page cache中挂更大的span也是可以的,根据具体的需求进行设置就行了

申请内存:

1、当central cache向page cache申请内存时,page cache先检查对应位置有没有span,如果没有则向更大页寻找一个span,如果找到则分裂成两个。比如:申请的是4页page,4页page后面没有挂span,则向后面寻找更大的span,假设在10页page位置找到一个span,则将10页page span分裂为一个4页pagespan和一个6页page span。
2、如果找到_spanList[1,128]都没有合适的span,则向系统使用mmap、brk或者是VirtualAlloc等方式申请128页page span挂在自由链表中,再重复1中的过程。
3、需要注意的是central cache和page cache的核心结构都是spanlist的哈希桶,但是他们是有本质 区别的,central cache中哈希桶,是按跟threadcache一样的大小对齐关系映射的,他的spanlist 中挂的span中的内存都被按映射关系切好链接成小块内存的自由链表。而pagecache中的spanlist则是按下标桶号映射的,也就是说第i号桶中挂的span都是i页内存

释放内存:

1、 如果central cache释放回一个span,则依次寻找span的前后page id的没有在使用的空闲span,看是否可以合并,如果合并继续向前寻找。这样就可以将切小的内存合并收缩成大的span,减少内存碎片。

小结

今日的分享就到这里啦,虽然没有任何的代码,但是大家一定一定要掌握好三层内存申请的结构,这对我们后面理解以及撰写代码非常重要,后面,我将会把这三层申请内存的架构再详细介绍给你

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

个人简历主页搭建系列-05:部署至 Github

前面只是本地成功部署网站&#xff0c;网站运行的时候我们可以通过 localhost: port 进行访问。不过其他人是无法访问我们本机部署的网站的。 接下来通过 Github Pages 服务把网站部署上去&#xff0c;这样大家都可以通过特定域名访问我的网站了&#xff01; 创建要部署的仓库…

U盘文件突然消失?原因与恢复策略全解析

一、遭遇不测&#xff1a;U盘文件突然消失 在日常生活和工作中&#xff0c;U盘扮演着不可或缺的角色&#xff0c;它小巧便捷&#xff0c;能够随时随地存储和传输文件。然而&#xff0c;有时我们会遭遇一个令人头疼的问题&#xff1a;U盘中的文件突然消失。这种突如其来的变故往…

Web漏洞-深入WAF注入绕过

目录 简要其他测试绕过 方式一:白名单&#xff08;实战中意义不大&#xff09; 方式二:静态资源 方式三: url白名单 方式四:爬虫白名单 #阿里云盾防SQL注入简要分析 #安全狗云盾SQL注入插件脚本编写 在攻防实战中&#xff0c;往往需要掌握一些特性&#xff0c;比如服务…

Linux CPU 占用率 100% 排查

Linux CPU 占用率 100% 排查 总体来说分为五个步骤 top 命令定位应用进程 pidtop -Hp [pid] 定位应用进程对应的线程 tidprintf “%x\n” [tid] 将 tid 转换为十六进制jstack [pid] | grep -A 10 [tid 的十六进制] 打印堆栈信息根据堆栈信息分析问题 以下为实战例子 写一段…

SQLBolt,一个练习SQL的宝藏网站

知乎上有人问学SQL有什么好的网站&#xff0c;这可太多了。 我之前学习SQL买了本SQL学习指南&#xff0c;把语法从头到尾看了个遍&#xff0c;但仅仅是心里有数的程度&#xff0c;后来进公司大量的写代码跑数&#xff0c;才算真真摸透了SQL&#xff0c;知道怎么调优才能最大化…

Autosar-Mcal配置详解(免费)-MCU

3.6.1创建、配置RAM 1)配置MCU通用配置项 MCU的通用配置项可参考以下配置&#xff1a; 各配置项的说明如下&#xff1a; Wake Up Factor Clear Isr: 是否在唤醒的中断服务函数中清除Wakeup Factor Wake Up Factors Clear Centralised: 是否在shutdown前集中集中清除Wakeu…

OpenHarmony动效示例-如何使用animateTo实现显式动画。

介绍 利用ArkUI组件不仅可以实现局部属性变化产生的属性动画&#xff0c;也可以实现父组件属性变化引起子组件产生过渡效果式的全局动画即显式动画。效果如图所示&#xff1a; 相关概念 显式动画&#xff1a;提供全局animateTo显式动画接口来指定有闭包代码导致的状态变化插入…

HarmonyOS 应用开发之启动/停止本地PageAbility

启动本地PageAbility PageAbility相关的能力通过featureAbility提供&#xff0c;启动本地Ability通过featureAbility中的startAbility接口实现。 表1 featureAbility接口说明 接口名接口描述startAbility(parameter: StartAbilityParameter)启动Ability。startAbilityForRes…

论文笔记:TALK LIKE A GRAPH: ENCODING GRAPHS FORLARGE LANGUAGE MODELS

ICLR 2024&#xff0c;reviewer评分 6666 1 intro 1.1 背景 当下LLM的限制 限制1&#xff1a;对非结构化文本的依赖 ——>模型有时会错过明显的逻辑推理或产生错误的结论限制2&#xff1a;LLMs本质上受到它们训练时间的限制&#xff0c;将“最新”信息纳入到不断变化的世…

如何保证redis里的数据都是热点数据

MySQL 里有 2000w 数据&#xff0c;Redis 中只存 20w 的数据&#xff0c;如何保证 redis 中的数据都是热点数据&#xff1f; 1.Redis 过期删除策略 1&#xff09;惰性删除:放任键过期不管&#xff0c;但是每次从键空间中获取键时&#xff0c;都检查取得的键是否过期&#xff0c…

FMEA与智能机器人:提升机器人可靠性与安全性的关键

随着科技的飞速发展&#xff0c;智能机器人已经深入到我们生活的方方面面&#xff0c;从工业生产到家庭服务&#xff0c;从深海探险到太空探索&#xff0c;处处都有它们的身影。然而&#xff0c;随着应用的日益广泛&#xff0c;机器人系统的复杂性和不确定性也在增加&#xff0…