【项目日记(五)】第二层: 中心缓存的具体实现(上)

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:项目日记-高并发内存池⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你做项目
  🔝🔝
开发环境: Visual Studio 2022


在这里插入图片描述

项目日记

  • 1. 前言
  • 2. 中心缓存的哈希桶结构
  • 3. span结构的具体实现
  • 4. 中心缓存类的定义
  • 5. 中心缓存如何分配小块儿内存?
  • 6. 中心缓存无内存时应该如何做?
  • 7. 总结

1. 前言

中心缓存起到一个承上启下的作用,
它负责给线程缓存分配小块儿的内
存,并且负责从页缓存申请大块儿内存

本章重点:

本篇文章着重讲解中心缓存的结构
包括span类的具体成员.并且会讲解
中心缓存是如何给线程缓存分配内存
并且是如何向页缓存申请/内存的!


2. 中心缓存的哈希桶结构

在对整个项目的结构做介绍的文章
中以及提到过中心缓存的结构了,
值得注意的是中心缓存使用的是桶锁
即每个哈希桶也就是每个spanlist都
又一个互斥锁

在这里插入图片描述


3. span结构的具体实现

span的具体结构:

shared.h文件:

//管理多个连续页的大块内存跨度结构,centralcache的哈希桶中链接的就是这种结构
class SpanData
{
public:PAGE_ID _pageid = 0;//32位下,程序地址空间,2^32byte,一页8kb=2^13byte,一共有2^19页size_t _n = 0;//页数SpanData* _next = nullptr;SpanData* _prev = nullptr;size_t _useCount = 0;//span中切分好的小对象有几个被使用了void* _freeList = nullptr;//切分好的小块内存的自由链表bool _isUse = false; //这个span是否正在被使用,若没有被使用则可能被pagecache合并成为大页size_t _objSize = 0; //切分好的小对象的大小,方便后面删除的时候可以直接知道它的大小
};
class SpanList//双向带头循环链表
{
public:SpanList(){_head = new SpanData;_head->_next = _head;_head->_prev = _head;}SpanData* Begin(){return _head->_next;}SpanData* End(){return _head;}bool Empty()//判断这个桶中是不是没有span{return _head->_next == _head;}void Insert(SpanData* pos, SpanData* newSpan){assert(pos && newSpan);SpanData* prev = pos->_prev;prev->_next = newSpan;newSpan->_prev = prev;newSpan->_next = pos;pos->_prev = newSpan;}void Erase(SpanData* pos){assert(pos);assert(pos != _head);/*if (pos == _head){int x = 0;}*/SpanData* prev = pos->_prev;SpanData* next = pos->_next;prev->_next = next;next->_prev = prev;}void PushFront(SpanData* span){Insert(Begin(), span);}SpanData* PopFront(){SpanData* front = _head->_next;Erase(front);return front;//erase中没有将此节点释放}SpanData* _head = nullptr;std::mutex _mtx;//桶锁
}; 

对成员变量use_count的解释:
use_count为0时,代表这个span
中所有被分配出去的小块儿内存
都被线程缓存还回来了,此时可直接
将这个span从中心缓存还给页缓存


4. 中心缓存类的定义

并且,中心缓存整体被设计为了单例模式:

CentralCache.h文件:

lass CentralCache
{
public:static CentralCache* GetInstance(){return &_singleton;}// 从中心缓存获取一定数量的对象(小块儿内存)给thread cachesize_t FetchRangeObj(void*& start, void*& end, size_t massNum, size_t size);//拿n个内存对象,大小是byte_size,start和end是输出型参数// 从SpanList获取一个非空的spanSpanData* GetOneSpan(SpanList& list, size_t size);// 将ThreadCache返回来的内存重新挂在CentralCache的spanvoid ReleaseListToSpans(void* start, size_t byte_size);
private:CentralCache(){}CentralCache(const CentralCache&) = delete;
private:SpanList _spanlist[N_FREE_LIST];//中心缓存的桶映射规则和Thread一样,208个桶static CentralCache _singleton;//单例模式
};
CentralCache CentralCache::_singleton = new CentreaCache();

5. 中心缓存如何分配小块儿内存?

FetchRangeObj函数我们并不陌生,
在线程缓存中,当桶中没有小块儿内存
时就是调用此函数来中心缓存获取的!

分配内存的基本步骤1:

中心缓存会先找到对应的哈希桶,然后
去桶中取一个非空的span结构,再将这
个span结构中切分好的小块儿内存分
配给线程缓存使用

CentralCache.h文件:

size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t massNum, size_t size)
{size_t index = AlignmentRule::Index(size);//找到对应的哈希桶_spanlist[index]._mtx.lock();//加锁SpanData* span = GetOneSpan(_spanlist[index], size);//从桶中获取一个span结构assert(span && span->_freeList);//从span中获取massnum个对象,若没有这么多对象的话,有多少就给多少start = span->_freeList;//把start指向首地址end = start;int factcount = 1;//实际分配给线程缓存的对象个数int i = 0;while (*(void**)end != nullptr && i< massNum - 1){end = *(void**)end;i++;factcount++;}span->_useCount += factcount;span->_freeList = *(void**)end;*(void**)end = nullptr;_spanlist[index]._mtx.unlock();//解锁return factcount;
}

6. 中心缓存无内存时应该如何做?

分配内存的基本步骤2:

若对应的哈希桶中的span为空,也
就是中心缓存无内存了,就会调用
NewSpan去页缓存获取一个新的
span结构,然后把新的span切分为
小块儿内存后再给线程缓存使用!

SpanData* CentralCache::GetOneSpan(SpanList& list, size_t size)
{SpanData* it = list.Begin();//遍历centralcache的中固定桶的所有span,若找到有不为空的freelist,则直接返回while (it != list.End()){if (it->_freeList != nullptr)//如果中心缓存有非空span,直接返回return it;elseit = it->_next;}//先把centralcache的桶锁解除,这样如果其他线程释放内存对象回来不会阻塞list._mtx.unlock();//走到这儿证明这个桶中没有span小对象了,去找pagecache要span//直接在这里将页缓存结构加锁,Newspan内就不用加锁了PageCache::GetInstance()->_mtx.lock();SpanData* span = PageCache::GetInstance()->NewSpan(AlignmentRule::NumMovePage(size));//传的参数是要申请的页数,size越大对应的页就应该越大span->_isUse = true;//将这个span的状态修改为正在使用span->_objSize = size;PageCache::GetInstance()->_mtx.unlock();//下面的内容不需要加锁,因为获取到的span只有我这个线程有,其他线程访问不到char* address = (char*)((span->_pageid) << PAGE_SHIFT); //这个页的起始地址是页号*8*1024,第0页的地址是0,以此类推size_t bytes = span->_n << PAGE_SHIFT; //计算这个span总共有多少个字节,用_n(页数)*8*1024//接下来要将这个span的大块内存切分成小块内存用自由链表连接起来char* end = address + bytes;//address和end对应空间的开头和结尾//1. 先切一块下来去做头,方便后续尾插span->_freeList = address;address += size;void* cur = span->_freeList;while (address < end)//2. 遍历空间尾插{*(void**)cur = address;cur = *(void**)cur;address += size;}*(void**)cur = nullptr;//插入时需要加锁,否则指向可能乱掉list._mtx.lock();list.PushFront(span);return span;
}

值得注意的是,获取到span后我们要通过这个span的页数来知道这个span有多少内存,并且要通过这个span在程序地址空间的页号来判断这份内存的起始地址是多少!第0页的地址是0000 0000,第一页的地址是8KB,以此类推

在这里插入图片描述


7. 总结

中心缓存这里给线程缓存分配内存时是
有两种情况的,当中心缓存无内存时就
会向页缓存索要,而本篇文章只讲解了
申请内存的过程,而当线程缓存将内存
还回来后,还有可能将span还给页缓存


🔎 下期预告:中心缓存的具体实现(下)🔍

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

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

相关文章

CentOS安装Redis教程-shell脚本一键安装配置

文章目录 前言一、Redis单机版安装教程1. 复制脚本2. 增加执行权限3. 执行脚本 二、Redis扩展集群版安装教程1. 安装Redis单机版2. 复制脚本3. 增加执行权限4. 执行脚本5. 测试6. redis_cluster.sh 命令6.1 启动Redis扩展集群6.2 停止Redis扩展集群6.3 查看Redis扩展集群节点信…

AI编译器的前端优化策略

背景 工作领域是AI芯片工具链相关&#xff0c;很多相关知识的概念都是跟着项目成长建立起来&#xff0c;但是比较整个技术体系在脑海中都不太系统&#xff0c;比如项目参与中涉及到了很多AI编译器开发相关内容&#xff0c;东西比较零碎&#xff0c;工作中也没有太多时间去做复盘…

Docker容器(自定义镜像,Dockerfile,网桥,DockerCompose)

自定义镜像 镜像就是包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。 构建步骤 镜像结构 Dockerfile 它是一个文本文件&#xff0c;包含很多指令&#xff0c;用指令来说明要执行什么操作来构建镜像。 官网&am…

【漏洞复现】友讯D-Link路由器弱口令漏洞

Nx01 产品简介 友讯电子设备&#xff08;上海&#xff09;有限公司于2002年8月13日成立。公司经营范围包括区内以路由器、网络卡、集线器、交换器、转换器等。 Nx02 漏洞描述 友讯D-Link路由器存在默认口令(admin/admin)&#xff0c;攻击者可利用该漏洞获取敏感信息。 Nx03 产…

windows .vscode的json文件配置 CMake 构建项目 调试窗口中文设置等

一、CMake 和 mingw64的安装和环境配置 二、tasks.json和launch.json文件配置 tasks.json {"version": "2.0.0","options": {"cwd": "${workspaceFolder}/build"},"tasks": [{"type": "shell&q…

软件设计师——计算机网络(四)

&#x1f4d1;前言 本文主要是【计算机网络】——软件设计师——计算机网络的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1…

react中优化类名写法(类似与vue的动态class对象方式)

安装和引入方式 npm install classnamesimport classNames form classsnames//render 方法中&#xff0c;需要动态className的地方直接参照上图使用

【NodeJS JS】动态加载字体的各方式及注意事项;

首先加载字体这个需求基本只存在于非系统字体&#xff0c;系统已有字体不需要加载即可直接使用&#xff1b; 方案1&#xff1a;创建 style 标签&#xff0c;写入 font-face{font-family: xxx;src: url(xxx)} 等相关字体样式&#xff1b;将style标签添加到body里&#xff1b;方…

C++学习| QT下载安装、VS配置QT

QT介绍 Qt&#xff1a;1991年由Qt Company开发的跨平台C图形用户界面应用程序开发框架。 应用&#xff1a;既可以开发GUI程序&#xff0c;也可用于开发非GUI程序&#xff0c;比如控制台工具和服务器。 对比MFC&#xff1a;MFC和QT两者都是用于C图形用户界面应用程序。 跨平…

念念不忘智能编程,必有回响CodeArts Snap

开发者的碎碎念 之前在【我与ModelArts的故事】的文章里&#xff0c;分享过我学习新技术的经历&#xff0c;主要有&#xff1a; 自主学习&#xff0c;比如自学Python&#xff1b;借助华为云的产品边用边学。 在围着"编程学习"这座城池&#xff0c;外围来来回回转了…

适用于 Windows 的 10 个最佳数据恢复工具学习

在数字时代&#xff0c;数据就是一切。从珍贵的家庭照片和重要的工作文档到最喜欢的音乐和电影&#xff0c;我们的生活越来越多地存储在各种设备上。系统崩溃、意外删除或恶意病毒都可能使您的宝贵数据瞬间消失。这就是数据恢复工具的用武之地。 10 个最佳数据恢复工具 这些软…

3 JS类型 值和变量

计算机对value进行操作。 value有不同的类型。每种语言都有其自身的类型集合。编程语言的类型集是该编程语言的基本特性。 value需要保存一个变量中。 变量的工作机制是变成语言的另一个基本特性。 3.1概述和定义 JS类型分为&#xff1a; 原始类型和对象类型。 原始类型&am…

消除游戏(第十三届蓝桥杯省赛C++C组 , 第十三届蓝桥杯省赛PythonA/B/研究生组)

在一个字符串 S 中&#xff0c;如果 SiSi−1 且 Si≠Si1&#xff0c;则称 Si 和 Si1 为边缘字符。 如果 Si≠Si−1 且 SiSi1&#xff0c;则 Si−1和 Si 也称为边缘字符。 其它的字符都不是边缘字符。 对于一个给定的串 S&#xff0c;一次操作可以一次性删除该串中的所有边缘…

python爬虫实战——自动话获取淘宝商品数据

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: python 3.8 pycharm 专业版 三方库: DrissionPage >>> pip install DrissionPage 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 pip install 模块名 (pip install requests) …

go语言(十九)---- channel

channel的使用 //1. 发送value到channelchannel <- value //2. 接收并将其丢弃<- channel //3. 从channel中接收数据&#xff0c;并将其赋值给x x : <- channel 例子 package mainimport "fmt"func main() {//定义一个channelc : make(chan int)go func…

【数据结构与算法】5.详解双向链表的基本操作(Java语言实现)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢迎各位大佬指点&…

SpringBoot之时间数据前端显示格式化

背景 在实际我们通常需要在前端显示对数据操作的时间或者最近的更新时间&#xff0c;如果我们只是简单的使用 LocalDateTime.now()来传入数据不进行任何处理那么我们就会得到非常难看的数据 解决方式&#xff1a; 1). 方式一 在属性上加上注解&#xff0c;对日期进行格式…

LeetCode.42. 接雨水

题目 题目链接 分析 读完本题以及结合题目给出的图我们可以很直观的看到&#xff0c;这道题目是让我们求形成凹槽的面积。 我们可以针对每一个数字形成凹槽的面积进行计算&#xff0c;然后相加数组每一个数字形成凹槽的面积即可。 那么问题来了&#xff0c;怎么知道一个数…

【Java与网络6】实现一个自己的HTTP浏览器

前面我们讨论了HTTP协议的基本结构和Socket编程的基本原理&#xff0c;本文我们来整个大活&#xff1a;自己实现一个简单的浏览器。 目录 1.主线程循环体 2.readHostAndPort()方法的实现 3.readHttpRequest()方法的实现 4.sendHttpRequest()方法的实现 5.readHttpRespons…

深度强化学习(王树森)笔记03

深度强化学习&#xff08;DRL&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接&#xff1a;https://github.com/wangshusen/DRL 源代码链接&#xff1a;https://github.c…