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

高并发内存池------内存释放

 一、将一定数量的对象释放到span跨度

 

// 将一定数量的对象释放到span跨度void 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--;// 说明span切分出去的小块内存都回来了// 这个span就可以再回收给pagecache,pagecache可以再尝试进行前后页的合并、if (span->_useCount == 0){_spanLists[index].Erase(span);span->_freeList = nullptr;span->_next = nullptr;span->_prev = nullptr;// 释放span给pagecache时,使用pagecache的锁就好了// 解掉桶锁_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();}

        从代码来看,ReleaseListToSpans 函数的功能是将一定数量的对象释放到 Span 中,并且在 Span 的使用计数为 0 时,将 Span 释放回 PageCache。这个函数涉及多线程同步(通过锁)和资源管理。以下是对代码的分析和一些需要注意的地方:

1. 代码分析

1.1 锁的使用
  • _spanLists[index]._mtx.lock()_spanLists[index]._mtx.unlock() 用于保护 _spanLists[index] 的操作,确保线程安全。

  • PageCache::GetInstance()->_pageMtx.lock()PageCache::GetInstance()->_pageMtx.unlock() 用于保护 PageCache 的操作,确保线程安全。

1.2 对象释放逻辑
  • 遍历对象链表,将每个对象加入到对应的 Span_freeList 中。

  • 每次释放一个对象时,span->_useCount 减 1。

  • 如果 span->_useCount 为 0,说明该 Span 的所有对象都已释放,可以将 Span 释放回 PageCache

1.3 锁的嵌套
  • 在释放 Span 时,先解锁 _spanLists[index]._mtx,然后加锁 PageCache::GetInstance()->_pageMtx,最后再次加锁 _spanLists[index]._mtx

  • 这种锁的嵌套需要特别小心,否则可能导致死锁或竞态条件。

2. 代码优化和改进建议

2.1 锁的优化
  • 减少锁的持有时间:尽量减少锁的持有时间,以提高性能。

  • 避免锁的嵌套:如果可能,尽量避免锁的嵌套。如果必须嵌套,确保嵌套顺序一致,避免死锁。

2.2 错误处理
  • 空指针检查:在访问指针(如 span)之前,确保指针不为空。

  • 异常安全:确保在发生异常时,锁能够正确释放。

2.3 代码可读性
  • 注释:增加注释,解释每个步骤的目的。

  • 函数拆分:将复杂的逻辑拆分成多个函数,提高代码可读性。

二、 释放对象时,链表过长时,回收内存回到中心缓存

 // 释放对象时,链表过长时,回收内存回到中心缓存void ListTooLong(FreeList& list, size_t size){void* start = nullptr;void* end = nullptr;list.PopRange(start, end, list.MaxSize());CentralCache::GetInstance()->ReleaseListToSpans(start, size);}

三、释放空闲span到pagecache,并合并相邻的span

 //释放空闲span到pagecache,并合并相邻的spanvoid ReleaseSpanToPageCache(Span* span){//对span前后的页尝试进行合并,缓解内存碎片的问题while (1){PAGE_ID prevId = span->_pageId - 1;auto ret = _idSpanMap.find(prevId);//前面的页号没有,不合并if(ret == _idSpanMap.end()){break;}//前面相邻页的span在使用,不合并了Span* prevSpan = ret->second;if(prevSpan->_isUse == true){break;}//合并后超过128页的span没办法管理,不合并if(prevSpan->_n + span->_n > NPAGES - 1){break;}span->_pageId = prevSpan ->_pageId;span->_n += prevSpan->_n;_spanLists[prevSpan->_n].Erase(prevSpan);delete prevSpan;}//向后合并while(1){PAGE_ID nextId = span->_pageId + span->_n;auto ret = _idSpanMap.find(nextId);if(ret == _idSpanMap.end()){break;}Span* nextSpan = ret->second;if(nextSpan->_isUse == true){break;}if(nextSpan->_n + span->_n > NPAGES - 1){break;}span->_n += nextSpan->_n;_spanLists[nextSpan->_n].Erase(nextSpan);delete nextSpan;}_spanLists[span->_n].PushFront(span);span->_isUse = false;_idSpanMap[span->_pageId] = span;_idSpanMap[span->_pageId + span->_n - 1] = span;}

        这段代码的功能是将一个空闲的 Span 释放到 PageCache 中,并尝试合并相邻的 Span,以减少内存碎片。以下是对代码的详细分析和改进建议。

1. 代码分析

1.1 向前合并逻辑
  • prevId:计算当前 Span 前一个页面的 ID。

  • _idSpanMap.find(prevId):查找前一个页面的 Span

  • 合并条件

    • 如果前一个 Span 未使用(prevSpan->_isUse == false)。

    • 合并后的 Span 大小不超过 NPAGES - 1

  • 合并操作

    • 更新当前 Span_pageId_n

    • _spanLists 中移除前一个 Span

    • 删除前一个 Span

1.2 向后合并逻辑
  • nextId:计算当前 Span 后一个页面的 ID。

  • _idSpanMap.find(nextId):查找后一个页面的 Span

  • 合并条件

    • 如果后一个 Span 未使用(nextSpan->_isUse == false)。

    • 合并后的 Span 大小不超过 NPAGES - 1

  • 合并操作

    • 更新当前 Span_n

    • _spanLists 中移除后一个 Span

    • 删除后一个 Span

1.3 最终操作
  • 将当前 Span 插入到 _spanLists 中。

  • 更新 _idSpanMap,确保当前 Span 的起始和结束页面 ID 都指向该 Span

相关文章:

  • Linux | mdadm 创建软 RAID
  • JavaScript性能优化实战(11):前沿技术在性能优化中的应用
  • NPN、PNP三极管的应用
  • JMeter 教程:编写 POST 请求脚本访问百度
  • 前端面经13 JS设计模式
  • 如果丝杆有轴向窜动应如何处理?
  • CAS(Compare-And-Swap)详解
  • 操作系统:os概述
  • Ansible模块——设置软件仓库和安装软件包
  • 动态规划-64.最小路径和-力扣(LetCode)
  • list重点接口及模拟实现
  • 最小二乘法拟合直线,用线性回归法、梯度下降法实现
  • git提交库常用词
  • 基于CentOS7制作OpenSSL 1.1的RPM包
  • DeepSeek超大模型的高效训练策略
  • PowerBI企业运营分析——RFM模型分析
  • 山东大学计算机图形学期末复习9——CG12上
  • Zephyr OS 中的 FIFO 接口应用介绍
  • deepin v23.1 音量自动静音问题解决
  • 【汇总】影视仓接口地址,影视仓最新配置接口【2025.5】
  • 61岁云浮市律师协会副会长谭炳光因突发疾病逝世
  • 习近平就乌拉圭前总统穆希卡逝世向乌拉圭总统奥尔西致唁电
  • 媒体:中国女排前队长朱婷妹妹被保送浙大受质疑,多方回应
  • 河南:响鼓重锤对违规吃喝问题露头就打、反复敲打、人人喊打
  • 奥迪车加油时频繁“跳枪”维修两年未解决,4S店拒退换:可延长质保
  • 法治课|争议中的“行人安全距离”于法无据,考量“注意义务”才更合理