当前位置: 首页 > news >正文

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

0

内存回收

  • 1.ThreadCache
  • 2.CentralCache
  • 3.PageCache

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

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 cacheif (_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需要将一页一一页的小块内存何合并成一张大页的内存,来解决内存碎片问题,因为大的可以切成小的,而当申请的内存大于小块的内存碎片时,就会向堆中申请,造成内存浪费。

点赞支持~

请添加图片描述

http://www.lryc.cn/news/212154.html

相关文章:

  • [毕设记录]@学术工具体验:Sread.ai
  • uboot - 驱动开发 - 驱动模型
  • windows 操作系统命令积累
  • 数据结构单链表的实现(C语言)
  • Postman的高级使用,傻瓜式学习【下】
  • Qt:关闭对话框,动画实现窗体逐渐缩小到消失
  • 在Windows上 ciphey安装(详细版)
  • 【lesson2】数据库的库操作
  • Android Studio Giraffe解决gradle reload failed问题
  • 刷题笔记day06-哈希表
  • springboot项目中如何实现过滤器鉴权
  • 【rust/esp32】在idf中使用embedded-graphics控制st7789 LCD屏幕
  • YOLOv8如何添加注意力模块?
  • 用LibreOffice在excel中画折线图
  • RabbitMQ 链接管理-发布者-消费者
  • JAVA中的垃圾回收器(3)----ZGC
  • IDEA 如何运行 SpringBoot 项目
  • Linux MeterSphere测试平台远程访问你不会?来试试这篇文章
  • 15.k8s集群防火墙配置
  • Python beautifulsoup网络抓取和解析cnblog首页帖子数据
  • Java集成腾讯云OCR身份证识别接口
  • C++之C++11引入enum class与传统enum关键字总结(二百五十一)
  • 如何将word格式的文档转换成markdown格式的文档
  • Leetcode—2558.从数量最多的堆取走礼物【简单】
  • 【如何写论文】硕博学位论文的结构框架、过程与大纲分析
  • 砷化镓(GaAs)纳米线 砷化镓纳米线 GaAs纳米线 瑞禧
  • PostGreSQL:JSON|JSONB数据类型
  • 树----数据结构
  • GitLab定时备份
  • SQL IN 运算符