【项目日记(八)】第三层: 页缓存的具体实现(下)

news2024/9/22 6:42:33

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

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

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

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


在这里插入图片描述

项目日记

  • 1. 前言
  • 2. 什么是内存碎片问题?
  • 3. 地址空间上的内存使用情况
  • 4. 页缓存合并内存的代码实现
  • 5. 总结以及对代码的拓展

1. 前言

请先看完页缓存的具体实现(上)

本章重点:

本篇文章着重讲解页缓存是怎样把从中心缓存中还回来的内存挂在桶上,并且进行前后页的内存合并的,合并内存形成更大的一份内存来减少内存碎片的问题


2. 什么是内存碎片问题?

我们拿整个程序地址空间来举例:

在这里插入图片描述

可以看见虽然整个程序地址空间还有300多byte的空间,但是要申请300byte却申请不出来,对于我们这个项目来说,假设有两个在地址空间中相邻的span,一个是10页,一个是15页,分别挂在第10号桶和第15号桶中,假设没有合并内存此时外部申请一个20页的span是申请不出来的,即使现在空闲的空间有25页,所以这也就体现出了这个项目中合并内存的重要性!


3. 地址空间上的内存使用情况

在地址空间中,一共是4GB大小的空间.
地址从0000 0000到FFFF FFFF.

第0页的起始地址是0
第一页的起始地址是8*1024KB
...以此类推

在这里插入图片描述

当中心缓存还回来一个span后,假设这个span中的大页内存在地址空间中是在第1000页,并且span的大小是50页,那么这个还回来的span就处于空闲状态了,此时我们只需要去检查地址空间中第999页的内存是否空闲,如果空闲就将1000~1050页和999页合并,形成一个51页的大块儿span,并且要不断向前合并直到遇见正在使用的页.同理,需要检查地址空间的1051页是否空闲,如果是空闲的,那么就将它一起合并过去!

在这里插入图片描述


4. 页缓存合并内存的代码实现

在pagecache.h文件中:

void PageCache::ReleaseSpanToPageCache(SpanData* span)
{
	if (span->_n > N_PAGES - 1)//大于128页的内存直接还给堆,不需要走pagecache
	{
		void* ptr = (void*)(span->_pageid << PAGE_SHIFT);
		SystemFree(ptr);
		//delete span;
		_spanPool.Delete(span);
		return;
	}
	//对span前后的页尝试进行合并,缓解外碎片问题
	while (1)//不断往前合并,直到遇见不能合并的情况
	{
		PAGE_ID prevId = span->_pageid - 1;
		auto prevret = _idSpanMap.find(prevId);
		if (prevret == _idSpanMap.end())//前面没有页号了
			break;
		SpanData* prevspan = ret;
		if (ret == nullptr)
			break;
		if (prevspan->_isUse == true)//前面的页正在使用
			break;
		if (prevspan->_n + span->_n > N_PAGES - 1)//当前页数加上span的页数大于128了,pagecache挂不下了
			break;
		//开始合并span和span的前面页
		span->_pageid = prevspan->_pageid;
		span->_n += prevspan->_n;
		_spanList[prevspan->_n].Erase(prevspan);//将被合并的页从pagecache中拿下来
		//delete prevspan;//将prevspan中的数据清除,诸如页号,页数等
		_spanPool.Delete(prevspan);
	}
	while (1)//不断往后合并,直到遇见不能合并的情况
	{
		PAGE_ID nextId = span->_pageid + span->_n;
		auto nextret = _idSpanMap.find(nextId);
		if (nextret == _idSpanMap.end())//前面没有页号了
			break;
		//SpanData* nextspan = nextret->second;
		auto ret = (SpanData*)_idSpanMap.get(nextId);
		if (ret == nullptr)
			break;
		SpanData* nextspan = ret;
		if (nextspan->_isUse == true)//前面的页正在使用
			break;
		if (nextspan->_n + span->_n > N_PAGES - 1)//当前页数加上span的页数大于128了,pagecache挂不下了
			break;
		//开始合并span和span的前面页
		span->_n += nextspan->_n;
		_spanList[nextspan->_n].Erase(nextspan);//将被合并的页从pagecache中拿下来
		//delete nextspan;//将prevspan中的数据清除,诸如页号,页数等
		_spanPool.Delete(nextspan);
	}
	//合并完后将span挂起来
	_spanList[span->_n].PushFront(span);
	//合并完后,要重新将这个span的首尾两页的id和这个span进行映射,方便别的span来合并我的时候使用
	_idSpanMap[span->_pageid] = span;
	_idSpanMap[span->_pageid + span->_n - 1] = span;
	span->_isUse = false;
}

对于代码的解释都在注释当中,大家可以发现整个合并内存的过程中,我们已经将delete操作符替换为了定长池中的free,这也就是完全脱离了free函数,并且当合并后的页数大于了128,此时整个页缓存哈希桶是挂不下的,所以要特别注意这一种情况


5. 总结以及对代码的拓展

页缓存结构的讲解已经结束,现在回头来看前面设计的这三层缓存结构,可谓是非常之巧妙,第一层线程缓存是无锁的,申请/释放内存非常高效,而第二层中心缓存是用的桶锁,在大多数情况下也没有竞争锁的问题,效率也非常高,所以现在能理解为什么要设计三层而不是两层,甚至是一层,一方面是为了效率的考量,另一方面是为了可以方便合并相邻的空闲页

对代码的拓展:

在使用到了直接向系统返还内存的函数:

inline static void SystemFree(void* ptr)
{
#ifdef _WIN32
	VirtualFree(ptr, 0, MEM_RELEASE);
#else
	// sbrk unmmap等
#endif
}

同样,这份代码知道就行了,不需详谈


🔎 下期预告:项目的测试以及优化🔍

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

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

相关文章

在windows和Linux中的安装 boost 以及 安装 muduo 和 mysql

一、CMake安装 Ubuntu Linux 下安装和卸载cmake 3.28.2版本-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/135960115?spm1001.2014.3001.5501二、安装boost boost官网&#xff1a;boost官网 我下载的boost版本&#xff1a; windows:boost_1_84_0.zipli…

基于SpringBoot的家电销售展示网页的设计与实现

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

k8s Sidecar filebeat 收集容器中的trace日志和app日志

目录 一、背景 二、设计 三、具体实现 Filebeat配置 K8S SideCar yaml Logstash配置 一、背景 将容器中服务的trace日志和应用日志收集到KAFKA&#xff0c;需要注意的是 trace 日志和app 日志需要存放在同一个KAFKA两个不同的topic中。分别为APP_TOPIC和TRACE_TOPIC 二、…

vulhub中spring的CVE-2022-22947漏洞复现

Spring Cloud Gateway是Spring中的一个API网关。其3.1.0及3.0.6版本&#xff08;包含&#xff09;以前存在一处SpEL表达式注入漏洞&#xff0c;当攻击者可以访问Actuator API的情况下&#xff0c;将可以利用该漏洞执行任意命令。 参考链接&#xff1a; https://tanzu.vmware.c…

SpringBoot security 安全认证(三)——自定义注解实现接口放行配置

背景&#xff1a;通过Security实现了安全管理&#xff0c;可以配置哪些接口可以无token直接访问。但一个麻烦就是每增加一个匿名访问接口时都要去修改SecurityConfig配置&#xff0c;从程序设计上讲是不太让人接受的。 本节内容&#xff1a;即是解决以上问题&#xff0c;增加一…

获取未来的5分钟整点时间05,10,15,20,25...

比如预约网约车的时候&#xff0c;是按5分钟的整点时间 GetMapping("/getFiveNextTime")public String fiveNextTime(RequestParam(defaultValue "0") Integer interval) {Calendar calendar Calendar.getInstance();calendar.add(Calendar.MINUTE, (5 …

MySQL进阶45讲【13】为什么表数据删掉一半,表文件大小不变?

1 前言 有些小伙伴在删数据库数据时&#xff0c;会产生一个疑问&#xff0c;我的数据库占用空间大&#xff0c;我把一个最大的表删掉了一半的数据&#xff0c;怎么表文件的大小还是没变&#xff1f; 那么这篇文章&#xff0c;就介绍一下数据库表的空间回收&#xff0c;看看如…

以太网帧格式及ARP协议简介

在以太网中&#xff0c;一个主机和另一个主机进行通信&#xff0c;必须要知道目的主机的MAC地址&#xff08;物理地址&#xff09;&#xff0c;只要知道目的主机的IP地址&#xff0c;就可以通过ARP协议获取目的主机的MAC地址。 1、ARP协议简介 ARP&#xff08;Address Resolut…

leetcode刷题(剑指offer) 297.二叉树的序列化和反序列化

297.二叉树的序列化与反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作&#xff0c;进而可以将转换后的数据存储在一个文件或者内存中&#xff0c;同时也可以通过网络传输到另一个计算机环境&#xff0c;采取相反方式重构得到原数据。 请设计一个算法来实现…

C语言-2

自定义类型 基本认识 /*引入&#xff1a;学生&#xff1a;姓名&#xff0c;学号&#xff0c;年龄&#xff0c;成绩请为学生们专门定制一个类型&#xff08;创造一个类型&#xff09;结构体格式&#xff1a;struct 标识符 // 标识符即自定义类型的名称{成员; // 自己设置…

H5 自适应超人背景引导页源码

H5 自适应超人背景引导页源码 源码介绍&#xff1a;一款自适应引导页源码&#xff0c;带超人背景。有四个跳转按钮。 下载地址&#xff1a; https://www.changyouzuhao.cn/11608.html

深度学习实战 | 卷积神经网络LeNet手写数字识别(带手写板GUI界面)

引言 在深度学习领域&#xff0c;卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种广泛应用于图像识别任务的神经网络结构。LeNet是一种经典的CNN结构&#xff0c;被广泛应用于基础的图像分类任务。本文将介绍如何使用LeNet卷积神经网络实现手写…

yum命令下载出现Failed to synchronize cache for repo ‘AppStream‘, ignoring this repo.

修改下面的配置文件 问题&#xff1a; cd /etc/yum.repos.d 修改下面四个文件 vim CentOS-Base.repo vim CentOS-AppStream.repo vim CentOS-Extras.repo vim CentOS-PowerTools.repo测试yum是否正常 yum -y install wget

极速搭建幻兽帕鲁私服,叫上好友春节假期一起联机畅玩帕鲁

文章目录 前言幻兽帕鲁私服详细部署教程查看服务器开始游戏自定义游戏参数配置 前言 行业资讯 《幻兽帕鲁》的火爆对开发商 Pocketpair 来说&#xff0c;代价是巨大的。该游戏的成功让首席执行官沟部拓郎最近在推特上表示&#xff0c;他可能因服务器运营费用而面临破产。据他透…

[文本挖掘和知识发现] 03.基于大连理工情感词典的情感分析和情绪计算

作者于2023年8月新开专栏——《文本挖掘和知识发现》&#xff0c;主要结合Python、大数据分析和人工智能分享文本挖掘、知识图谱、知识发现、图书情报等内容。这些内容也是作者《文本挖掘和知识发现&#xff08;Python版&#xff09;》书籍的部分介绍&#xff0c;本书预计2024年…

vscode 括号 python函数括号补全

解决方法 在setting.json中添加 “python.analysis.completeFunctionParens”: true 打开设置&#xff1b; 点击图中按钮打开setting.json文件 添加 “python.analysis.completeFunctionParens”: true

管理类联考-复试-全流程演练-导航页

文章目录 整体第一步&#xff1a;学校导师两手抓——知己知彼是关键学校校训历史 导师 第二步&#xff1a;面试问题提前背——押题助沟通自我介绍——出现概率&#xff1a;100%为什么选择这个专业&#xff1f;今后如何打算&#xff1f;你认为自己本科专业和现在所考的专业有什么…

嵌入式linux移植篇之Uboot

什么是bootloader&#xff1f; 芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等外设&#xff0c;然后将Linux内核从flash(NAND&#xff0c;NOR FLASH&#xff0c;SD&#xff0c;MMC 等)拷贝到 DDR 中&#xff0c;最后启动 Linux 内核。当然了&#…

分享5款让人眼前一亮的软件

​ 让你眼前一亮的软件&#xff0c;不一定是市面上最流行的。今天&#xff0c;我将推荐给你五款非常小众&#xff0c;但是十分好用的软件。 1.自动化脚本——AutoIt ​ AutoIt是一款自动化脚本软件&#xff0c;可以让你编写和运行一些简单的程序&#xff0c;实现一些重复性或…