《C++实战项目-高并发内存池》5.PageCache构造

💡Yupureki:个人主页

✨个人专栏:《C++》 《算法》《Linux系统编程》《高并发内存池》


🌸Yupureki🌸的简介:


目录

[1. PageCache框架初识](#1. PageCache框架初识)

[2. PageCache框架构造](#2. PageCache框架构造)

[3. PageCache类初步构造](#3. PageCache类初步构造)


1. PageCache框架初识

申请内存:

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

释放内存:

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

2. PageCache框架构造

PageCache具有以下成员变量

  1. _spanlists:一连串的SpanList哈希桶,每个SpanList中有一定的Span
  2. mutex:互斥锁,访问PageCache时,需要把整个PageCache锁上
  3. _pinst:单例模式
  4. //......最终方案肯定不只这些变量,等以后需要的时候再添加
cpp 复制代码
//单例模式
class PageCache
{
private:
	PageCache()
		:_spanlists(NPAGES)
	{ }
	PageCache(const PageCache&) = delete;
public:
	static PageCache& GetInstance()
	{
		return _pinst;
	}
	Span* NewSpan(size_t k);//PageCache获取Span,给CentralCache
	void Lock()
	{
		_mtx.lock();
	}
	void Unlock()
	{
		_mtx.unlock();
	}
	void ReleaseSpanToPageCache(Span* span);//CentralCache把多余的Span还给PageCache
private:
	std::vector<SpanList> _spanlists;
	std::mutex _mtx;
	static PageCache _pinst;
};

3. PageCache类初步构造

NewSpan:PageCache获取Span,给CentralCache

  1. 如果PageCache有多余的Span,直接给CentralCache
  2. 如果没有多余的,则往后找更大的页,然后分割(如没有大小为4页的内存块,向后找到了5页的内存块,则把5页分成4页和1页,4页给CentralCache,1页挂在哈希桶中)
  3. 如果往后找也没有多余的大内存块,则要从系统中申请128页的大内存块,然后重复步骤2
cpp 复制代码
// Span* PageCache::NewSpan(size_t k)
// 该方法用于从页面缓存中分配一个包含k个页面的Span对象。
// 如果k大于页面缓存的最大页面数量减一,则直接从系统分配内存。
// 如果k小于等于最大页面数量减一,则尝试从缓存中查找合适大小的Span。
// 如果未找到合适大小的Span,则查找大于k的最小Span,分割并返回k个页面。
// 如果缓存中没有可用的大块内存,则向系统申请最大块的内存并重新尝试分配。

// 获取一个K页的span
Span* PageCache::NewSpan(size_t k)
{
	assert(k > 0 && k < NPAGES);

	// 先检查第k个桶里面有没有span
	if (!_spanLists[k].Empty())
	{
		return _spanLists->PopFront();
	}

	// 检查一下后面的桶里面有没有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);

			return kSpan;
		}
	}

	// 走到这个位置就说明后面没有大页的span了
	// 这时就去找堆要一个128页的span
	Span* bigSpan = new Span;
	void* ptr = SystemAlloc(NPAGES - 1);//SystemAlloc在ObjectPool中实现了
	bigSpan->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT;
	bigSpan->_n = NPAGES - 1;

	_spanLists[bigSpan->_n].PushFront(bigSpan);

	return NewSpan(k);
}

ReleaseSpanToPageCache涉及到释放内存到系统中,我们等下一节:实现释放内存的章节中再实现

相关推荐
chenbingjie_c3 分钟前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++
是main不是漫4 分钟前
【双指针——移动零】数组划分类题目的入门基石
c++·算法
吴卫斌11 分钟前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
·present·20 分钟前
CSAPP(Bomb lab)
c语言·c++
王老师青少年编程32 分钟前
2026年信奥赛c++普及组csp-j第二轮复赛真题
c++·真题·csp·信奥赛
超级架构师1 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
时间的拾荒人2 小时前
CMake 常用命令详解:从版本声明到安装部署
c++·面试
叼烟扛炮2 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
LMT流氓兔3 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
专注仿真3 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法