【C++项目】高并发内存池第五讲内存回收释放过程介绍

这篇具有很好参考价值的文章主要介绍了【C++项目】高并发内存池第五讲内存回收释放过程介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++项目】高并发内存池第五讲内存回收释放过程介绍,C+方向实战项目,c++,开发语言

项目源代码:高并发内存池

1.ThreadCache

void ThreadCache::Deallocate(void* ptr, size_t size)
{
	assert(ptr);
	assert(size <= MAX_BYTES);

	//计算在哪号桶中,然后插入进去
	size_t index = SizeClass::Index(size);
	_freeLists[index].Push(ptr);


	//当链表长度大于一次批量申请的内存时就开始还一段list给central cache
	if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
	{
		ListTooLong(_freeLists[index], size);
	}
}

void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
	void* start = nullptr;
	void* end = nullptr;
	list.PopRang(start, end, list.MaxSize());
	CentralCache::GetInstance()->ReleaseListToSpans(start, size);
}

当闲置的内存超过一个批量单位大小的时候就开始回收,首先要计算出要回收到哪个桶的的内存,然后逐级往上回收。

2.CentralCache

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;
		span->_usecount--;
		if (span->_usecount == 0)
			//说明span切分出去的内存小块都回收回来了,
			//这时这个span就可以再回收给page cache,page cache可以再尝试去做前后页的合并
		{
			_spanLists[index].Erase(span);
			span->_freeList = nullptr;
			span->_prev = nullptr;
			span->_next = nullptr;

			//释放span给page cache时,使用page cache的锁就可以了
			//所以需要先把桶锁解掉再加page cache的大锁
			_spanLists[index]._mtx.unlock();
			PageCache::GetInstance()->_pageMtx.lock();
			PageCache::GetInstance()->ReleaseSpanToPageCache(span);
			PageCache::GetInstance()->_pageMtx.unlock();
			_spanLists[index]._mtx.lock();

		}
		start = next;
	}


	_spanLists[index]._mtx.unlock();

}

CentralCache回收回来还需要做前后页的合并,合成一个大的内存块,然后继续交给PageCache处理

3.PageCache


void PageCache::ReleaseSpanToPageCache(Span* span)
{
	//大于128页的span,直接还给堆
	if (span->_n > NPAGES -1)
	{
		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 ret = _idSpanMap.find(prevId);

		前面的页号没有找到,不进行合并
		//if (ret == _idSpanMap.end())
		//{
		//	break;
		//}
		
		auto ret = (Span*)_idSpanMap.get(prevId);
		if (ret == nullptr)
		{
			break;
		}
		//前面相邻页的span在使用,不进行合并
		Span* prevSpan = ret;
		if (prevSpan->_isUse == true)
		{
			break;
		}
		//合并出超过128的span没办法管理,就不能继续合并
		if (prevSpan->_n + span->_n > NPAGES - 1)
		{
			break;
		}

		//合并
		span->_pageId = prevSpan->_pageId;
		span->_n += prevSpan->_n;
		_spanList[prevSpan->_n].Erase(prevSpan);
		//delete prevSpan;
		_spanPool.Delete(prevSpan);

	}


	//向后合并
	while (1)
	{
		PAGE_ID nextId = span->_pageId + span->_n;
		/*auto ret = _idSpanMap.find(nextId);
		if (ret == _idSpanMap.end())
		{
			break;
		}*/
		auto ret = (Span*)_idSpanMap.get(nextId);
		if (ret == nullptr)
		{
			break;
		}
		Span* nextSpan = ret;
		if (nextSpan->_isUse == true)
		{
			break;
		}
		if (span->_n + nextSpan->_n > NPAGES - 1)
		{
			break;
		}
		span->_n += nextSpan->_n;

		_spanList[nextSpan->_n].Erase(nextSpan);
		//delete nextSpan;
		_spanPool.Delete(nextSpan);
	}
	_spanList[span->_n].PushFront(span);
	span->_isUse = false;
	//_idSpanMap[span->_pageId] = span;
	_idSpanMap.set(span->_pageId, span);
	//_idSpanMap[span->_pageId + span->_n - 1] = span;
	_idSpanMap.set(span->_pageId + span->_n - 1, span);
}

PageCache需要将一页一一页的小块内存何合并成一张大页的内存,来解决内存碎片问题,因为大的可以切成小的,而当申请的内存大于小块的内存碎片时,就会向堆中申请,造成内存浪费。

点赞支持~

【C++项目】高并发内存池第五讲内存回收释放过程介绍,C+方向实战项目,c++,开发语言文章来源地址https://www.toymoban.com/news/detail-718231.html

到了这里,关于【C++项目】高并发内存池第五讲内存回收释放过程介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Acwing linux 第五讲git

    代码部分我给大家在最后单独整一个页面好看,正文内容里面也有大家可以一边看一用!!!!!!!!!!!!!!!!!!!! 昨天讲了ssh内容,今天讲解git,git是个灰常重要的工具,所以我要给大家先讲一下陌生的git。 先放网上解释: Git  是一种 分布式版本控制系统

    2024年02月03日
    浏览(41)
  • 算法基础课第五讲 动态规划

    时间复杂度:状态数量 转移的计算量 * 总体概述:给一堆物品,有体积有价值。有一个背包,在背包能装下的前提下最终能装下多少(背包不一定要装满) DP问题:一般需要从两方面考虑:状态表示以及状态计算 状态表示:f(i,j) 从两个方面考虑:集合(所有选法的集合)(

    2024年02月01日
    浏览(47)
  • C++动态内存开辟与释放new和delete

    🐶博主主页: @ᰔᩚ. 一怀明月ꦿ  ❤️‍🔥 专栏系列: 线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,数据结构 🔥 座右铭: “不要等到什么都没有了,才下定决心去做” 🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

    2024年02月03日
    浏览(47)
  • C++中清空Vector内元素的方法以及释放内存

    初始化如下: 方法一: 使用 clear ,清空元素,但不回收空间 方法二: 使用 erase循环删除,结果同上 erase在每次操作时,迭代器指针会整体前移1,就是每次都会“搬”全部数据,所以vector不适合做频繁删除的容器。 方法三: 最简单的使用swap,清除元素并回收内存 这个做法

    2024年02月16日
    浏览(46)
  • Redis 7 第五讲 事务、管道、发布订阅 过渡篇

             可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞          一个队列中,一次性、顺序性、排他性的执行一系列命令 单独的隔离操作 Redis的事务仅仅是保证事务里的操

    2024年02月10日
    浏览(36)
  • 【视觉SLAM十四讲学习笔记】第五讲——相机模型

    专栏系列文章如下: 【视觉SLAM十四讲学习笔记】第一讲——SLAM介绍 【视觉SLAM十四讲学习笔记】第二讲——初识SLAM 【视觉SLAM十四讲学习笔记】第三讲——旋转矩阵 【视觉SLAM十四讲学习笔记】第三讲——旋转向量和欧拉角 【视觉SLAM十四讲学习笔记】第三讲——四元数 【视

    2024年01月17日
    浏览(39)
  • 60题学会动态规划系列:动态规划算法第五讲

    子数组系列题目 文章目录 1.最大子数组和 2.环形子数组的最大和 3.乘积最大数组 4.乘积为正数的最长子数组长度 5.等差数列划分 6.最长湍流子数组 7.单词拆分 8.环绕字符串中唯一的子字符串 力扣链接:力扣 给你一个整数数组  nums  ,请你找出一个具有最大和的连续子数组(

    2024年02月15日
    浏览(55)
  • C++多线程场景中的变量提前释放导致栈内存异常

    在子线程中尝试使用当前函数的资源 ,是非常危险的,但是C++支持这么做。因此C++这么做可能会造成栈内存异常。 上述是一个正常的多线程代码。 但是如果将其中多线程传参设置为引用传递,可能就会造成栈内存异常了,如下所示: 编译成功,但是运行失败。 运行结果:

    2024年02月13日
    浏览(56)
  • ElasticSearch第五讲 ES nested嵌套文档与父子文档处理

    在ES中,处理实体之间的关系并不像关系型存储那样明显。在关系数据库中的黄金准则 - 数据规范化,在ES中并不适用。在处理关联关系,嵌套对象和父子关联关系中,我们会讨论几种可行方案的优点和缺点。 紧接着在为可扩展性而设计中,我们会讨论ES提供的一些用来快速灵

    2024年02月02日
    浏览(43)
  • SpringMVC第五讲:SpringMVC实现AJAX及JSON格式转换

    10、1Spring MVC实现AJAX AJAX异步提交是页面与程序交互的重要手段之一,在SpringMVC中,也支持页面向Controller控制器发送异步请求。页面发送异步请求时,常使用JSON格式数据进行数据传输。但是当页面需要向Controller控制器发送异步请求时,需要注意以下几个问题: SpringMVC的静态

    2024年02月15日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包