【lesson8】高并发内存池Central Cache层释放内存的实现

文章目录

  • Central Cache层释放内存的流程
  • Central Cache层释放内存的实现

Central Cache层释放内存的流程

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

但是这里就有一个问题了,我们如何知道还回来的对象属于哪个span?
其实 对象的地址/8K 就是对应span的地址 为什么呢?
画图理解
画两个span并写出_pageid和计算出地址
在这里插入图片描述
这时又两个对象1和2
假设:
1的地址:FA1000
2的地址:FA3000

除以8k看他们对应的span是否正确。
在这里插入图片描述
从图中可知,之前的结论确实正确。
所以我们接下来只要把_pageId和对应的span进行map映射即可,用map存储对应的_pageId和span
这个map我们设置在page cache中,因为映射关系的写入全部在page cache中进行。

#pragma once#include "Common.h"class PageCache
{
private:SpanList _spanLists[NPAGES];//对应的spanstd::unordered_map<PAGE_ID, Span*> _idSpanMap;PageCache(){}PageCache(const PageCache&) = delete;static PageCache _sInst;
};

而接下来就是建立映射关系,只要有一个span被申请出去,那么我们就要建立映射关系一次
而只有NewSpan可以申请span所以就要修改NewSpan

// 获取一个K页的span
Span* PageCache::NewSpan(size_t k)
{assert(k > 0 && k < NPAGES);// 先检查第k个桶里面有没有spanif (!_spanLists[k].Empty()){Span* kSpan = _spanLists[k]->PopFront();// 建立id和span的映射,方便central cache回收小块内存时,查找对应的span//补充点1:画图补充便于理解for (PAGE_ID i = 0; i < kSpan->_n; ++i){_idSpanMap[kSpan->_pageId + i] = kSpan;}return kSpan;}// 检查一下后面的桶里面有没有span,如果有可以把他它进行切分for (size_t i = k+1; i < NPAGES; ++i){if (!_spanLists[i].Empty()){Span* nSpan = _spanLists[i].PopFront();Span* kSpan = new Span;// 在nSpan的头部切一个k页下来// k页span返回// nSpan再挂到对应映射的位置kSpan->_pageId = nSpan->_pageId;kSpan->_n = k;nSpan->_pageId += k;nSpan->_n -= k;_spanLists[nSpan->_n].PushFront(nSpan);// 存储nSpan的首位页号跟nSpan映射,方便page cache回收内存时// 方便之后进行的合并查找// 补充点2:画图便于理解_idSpanMap[nSpan->_pageId] = nSpan;_idSpanMap[nSpan->_pageId + nSpan->_n - 1] = nSpan;// 建立id和span的映射,方便central cache回收小块内存时,查找对应的spanfor (PAGE_ID i = 0; i < kSpan->_n; ++i){_idSpanMap[kSpan->_pageId + i] = kSpan;}return kSpan;}}// 走到这个位置就说明后面没有大页的span了// 这时就去找堆要一个128页的spanSpan* bigSpan = new Span;void* ptr = SystemAlloc(NPAGES - 1);bigSpan->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT;bigSpan->_n = NPAGES - 1;_spanLists[bigSpan->_n].PushFront(bigSpan);return NewSpan(k);
}

补充点1

 for (PAGE_ID i = 0; i < kSpan->_n; ++i){_idSpanMap[kSpan->_pageId + i] = kSpan;}

上面这段代码逻辑的具象化
在这里插入图片描述
补充点2

_idSpanMap[nSpan->_pageId] = nSpan;
_idSpanMap[nSpan->_pageId + nSpan->_n - 1] = nSpan;

上面代码是把Page Cache中还未使用的span放入map中进行映射以便page cache释放内存是合并
在这里插入图片描述
映射关系存入map中了,接下来Page Cache就要提供一个接口,来为我们查找是否有对应的映射

Span* PageCache::MapObjectToSpan(void* obj)
{//计算映射的页号PAGE_ID id = ((PAGE_ID)obj >> PAGE_SHIFT);//查找是否有该span,有则返回该span//只要没有,则一定是之前写的逻辑出现了问题auto ret = _idSpanMap.find(id);if (ret != _idSpanMap.end()){return ret->second;}else{assert(false);return nullptr;}
}

现在万事具备就只有实现Central Cache的释放流程了

Central Cache层释放内存的实现

void CentralCache::ReleaseListToSpans(void* start, size_t size)
{size_t index = SizeClass::Index(size);_spanLists[index]._mtx.lock();while (start){void* next = NextObj(start);//对象一个一个查找对应的映射关系Span* span = PageCache::GetInstance()->MapObjectToSpan(start);NextObj(start) = span->_freeList;span->_freeList = start;//还回来一个_useCount就减1//补充点1:_useCount++的逻辑span->_useCount--;// _useCount == 0说明span的切分出去的所有小块内存都回来了// 这个span就可以再回收给page cache,pagecache可以再尝试去做前后页的合并if (span->_useCount == 0){//先把span从对应的桶中删除_spanLists[index].Erase(span);//然后清空span中无用的数据span->_freeList = nullptr;span->_next = nullptr;span->_prev = nullptr;// 释放span给page cache时,使用page cache的锁就可以了// 这时把桶锁解掉_spanLists[index]._mtx.unlock();//归还span给Page Cache,让它处理PageCache::GetInstance()->_pageMtx.lock();//调用Page Cache内的释放函数PageCache::GetInstance()->ReleaseSpanToPageCache(span);PageCache::GetInstance()->_pageMtx.unlock();//恢复桶锁解掉_spanLists[index]._mtx.lock();}//走向下一个对象start = next;}_spanLists[index]._mtx.unlock();
}

补充点1:_useCount++的逻辑

// 从中心缓存获取一定数量的对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{size_t index = SizeClass::Index(size);_spanLists[index]._mtx.lock();Span* span = GetOneSpan(_spanLists[index], size);assert(span);assert(span->_freeList);// 从span中获取batchNum个对象// 如果不够batchNum个,有多少拿多少start = span->_freeList;end = start;size_t i = 0;size_t actualNum = 1;while ( i < batchNum - 1 && NextObj(end) != nullptr){end = NextObj(end);++i;++actualNum;}span->_freeList = NextObj(end);NextObj(end) = nullptr;//实际拿了多少个usecount给Thread Cache就加多少span->_useCount += actualNum;_spanLists[index]._mtx.unlock();return actualNum;
}

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

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

相关文章

[MFC] MFC消息机制的补充

之前写了[MFC] 消息映射机制的使用和原理浅析&#xff0c;还有些需要补充的&#xff0c;都记在这里。 MFC 消息的分类 MFC消息分为系统消息和自定义消息。 图片来源&#xff1a;C语言/C教程 大型源码案例分析&#xff1a;MFC消息系统的代码解析 易道云编程 系统消息分为窗口…

YOLOv5改进:下采样系列 |一种新颖的基于 Haar 小波的下采样HWD,有效涨点系列

💡💡💡本文独家改进:HWD的核心思想是应用Haar小波变换来降低特征图的空间分辨率,同时保留尽可能多的信息,与传统的下采样方法相比,有效降低信息不确定性。 💡💡💡使用方法:代替原始网络的conv,下采样过程中尽可能包括更多信息,从而提升检测精度。 收录 YO…

Python中的继承和super()

父类方法的调用 可以使用父类名.方法名来调用也可以使用super().方法名来调用 MRO顺序 Python官方采用了一个算法将复杂结构上所有的类全部都映射到一个线性顺序上&#xff0c;而根据这个顺序就能 够保证所有的类都会被构造一次。这个顺序就是MRO顺序。 查看MRO顺序 类名.…

【JavaWeb】头条新闻纯JavaWeb项目实现 项目搭建 数据库工具类导入 跨域问题 Postman 第一期 (前端Vue3+Vite)

文章目录 一、项目简介1.1 微头条业务简介1.2 技术栈介绍 二、项目部署三、准备工具类3.1 异步响应规范格式类3.2 MD5加密工具类3.3 JDBCUtil连接池工具类3.4 JwtHelper工具类3.4 JSON转换的WEBUtil工具类 四、准备各层的接口和实现类4.1 准备实体类和VO对象4.2 DAO层接口和实现…

Day17、18、19学习记录

#c语言知识 内存管理 1.作用域 &#xff08;1&#xff09;代码块作用域&#xff08;代码块是{}之间的一段代码&#xff09; &#xff08;2&#xff09;函数作用域 &#xff08;3&#xff09;文件作用域 2.局部变量&#xff08;自动变量auto&#xff09;&#xff1a; 在函…

快速理解复杂系统组成学习内容整合

目录 一、复杂系统组成 二、接入系统 (Access System) 三、应用系统 (Application System) 四、基础平台 (Foundation Platform) 五、中间件 (Abundant External Middleware) 六、支撑系统 (Supporting System) 参考文章 一、复杂系统组成 复杂系统是由多个相互关联、相…

2024程序员就业咋办?

国际研究机构Gartner会在每年10月份左右发布下一年度的战略发展趋势预测&#xff0c;并在次年3月左右发布和网络安全相关的趋势预测。绿盟科技通过将近3年的趋势预测进行分组对比分析后发现&#xff0c;除了众人皆知的AI技术应用外&#xff0c;数据模块化、身份优先安全、行业云…

【Java程序设计】【C00207】基于(JavaWeb+SSM)的宠物领养管理系统(论文+PPT)

基于&#xff08;JavaWebSSM&#xff09;的宠物领养管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的宠物领养系统 本系统分为前台系统、管理员、收养者和寄养者4个功能模块。 前台系统&#xff1a;游客打开系统…

AIGC时代企业与个人应该如何应对?

引言&#xff1a;AIGC是一种新兴的技术趋势&#xff0c;它正在为各个领域带来更多的创新和变革。未来&#xff0c;随着技术的不断进步和应用范围的扩大&#xff0c;AIGC的影响力还将不断增强。新时代下企业与个人应该如何应对呢&#xff1f; 1. 什么是AIGC&#xff1f; AIGC是…

[每日一题] 02.03 - 质因数分解

质因数分解 枚举到n的平方根&#xff08;得包括平方根&#xff09; 偶数去除 import math n int(input()) if n % 2 0:print(max(n // 2,2)) else:for i in range(3,int(math.sqrt(n)) 1,2):if n % i 0:print(max(n // i,i))

GrayLog踩坑历险记

背景 GrayLog作为ELK的替代产品&#xff0c;是新生代的日志采集框架。在一个采集节点日志的需求中&#xff0c;因为节点很多&#xff0c;产生的日志也很多&#xff0c;因此尝试了使用GrayLog进行日志的采集。下面记录一下使用GrayLog中遇到的坑和解决方案。 一、部署与启动 …

二、操作系统【6分】

一、课程内容提要 二、考情分析 三、操作系统概述 1、操作系统的功能 2、特殊的操作系统 四、进程管理 1、进程与线程的概念 2、进程的状态 3、信号量与PV操作 P是要资源 V是释放资源 互斥S初始值非0&#xff0c;一般为1&#xff0c;先p后v 同步S初始值一般为0&#xff0c…