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

高并发内存池(12)-ThreadCache回收内存

高并发内存池(12)-ThreadCache回收内存

代码如下:

// 释放对象时,链表过长时,回收内存回到中心缓存
void ThreadCache::ListTooLong(FreeList& list, size_t size)
{void* start = nullptr;void* end = nullptr;list.PopRange(start, end, list.MaxSize());CentralCache::GetInstance()->ReleaseListToSpans(start, size);
}
//还给Central的自由链表
void* PopRange(void*&start,void*&end,size_t n)
{assert(n <= _size);start = _freeList;end = start;for (size_t i = 0; i < n - 1; ++i){end = NextObj(end);}_freeList = NextObj(end);NextObj(end) = nullptr;_size -= n;
}

PopRange函数中使用引用参数(void*& start, void*& end)是极其重要的设计选择,有以下几个关键原因:

1. 需要修改调用方的变量

void* start_ptr = nullptr;
void* end_ptr = nullptr;
freeList.PopRange(start_ptr, end_ptr, 5);  // 需要修改start_ptr和end_ptr的值

如果没有引用

  • 函数内部修改的只是参数的副本
  • 调用方的变量不会被实际修改
  • 无法返回提取的内存块链表信息

2. 需要返回两个值

函数需要同时返回:

  • 批量链表的头指针start
  • 批量链表的尾指针end

C++函数只能直接返回一个值,所以必须通过参数返回另一个值。

替代方案对比:

方案1:使用引用参数(当前实现) ✅

void PopRange(void*& start, void*& end, size_t n);
// 清晰,高效,常用

方案2:返回结构体 ❌

struct RangeResult {void* start;void* end;
};
RangeResult PopRange(size_t n);
// 需要定义额外结构体,不够直观

方案3:使用指针参数 ❌

void PopRange(void** start, void** end, size_t n);
// 语法复杂,容易出错

3. 性能零开销

引用在底层通常通过指针实现,但:

  • 语法更简洁:像操作普通变量一样
  • 类型安全:编译器会检查类型匹配
  • 无性能损失:与指针方案性能相同

4. 代码可读性

对比两种写法:

使用引用(清晰)

void* start, *end;
freeList.PopRange(start, end, 5);
// 现在start和end包含了提取的链表

使用指针参数(复杂)

void* start, *end;
freeList.PopRange(&start, &end, 5);
// 需要取地址,容易忘记&

5. 在内存池中的具体应用

// CentralCache向ThreadCache提供内存
void CentralCache::FetchRangeObj(void*& start, void*& end, size_t n)
{// 需要修改start和end来返回内存块链表_freeList.PopRange(start, end, n);// 现在start和end包含了提取的内存块
}

如果不使用引用会怎样?

// 错误版本:不使用引用
void PopRange(void* start, void* end, size_t n)
{start = _freeList;  // 这只是修改局部副本!// 调用方的变量不会被修改
}// 调用代码
void* my_start, *my_end;
freeList.PopRange(my_start, my_end, 5);  // my_start和my_end仍然是nullptr!

总结

使用引用参数void*& start, void*& end是因为:

  1. 需要修改调用方的变量
  2. 需要返回两个值(链表头和尾)
  3. 语法简洁且类型安全
  4. 性能零开销
  5. 代码可读性好

这是C++中常用的"输出参数"模式,特别适合需要返回多个值的场景。在内存池这种高性能组件中,这种设计确保了接口的效率和简洁性。

http://www.dtcms.com/a/353506.html

相关文章:

  • Virtual PLCnext Controller 本地网络部署平台
  • Pandas DataFrame 列数操作完全指南
  • 高通平台蓝牙学习-- 基于WCN685x 的蓝牙低功耗(LE)功能
  • 浏览器与计算机网络
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘click’问题
  • k8s部署pgsql集群
  • 【Spring Cloud 微服务】5.架构的智慧枢纽:深度剖析 Nacos 注册中心
  • K8s持久化存储:PV与PVC
  • K8s 二次开发漫游录
  • 前端-npm和yarn的区别
  • 时序数据库的 LSM 树介绍
  • 计算机网络——DNS,ARP,RARP,DHCP,ICMP
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘websockets’问题
  • 时序数据库全景指南:从场景选型到内核拆解
  • Linux(十九)——CPU、I/O、网络与内核参数调优指南
  • 字库原理 GB2312-80
  • rk3588开发板最新kernel6.1下载(RK3588SDK源码下载)和环境搭建
  • 基于结构化码本的分层DNN框架用于高效语音增强
  • 第18章|变量:把数据装进“盒子”的正确方式
  • 【STM32】将 FreeRTOS移植到STM32F103RCT6 详细流程
  • 【开发配置】GitLab CR(Code Review)规则配置清单
  • 论文翻译:BRILLM: BRAIN-INSPIRED LARGE LANGUAGE MODEL
  • 在Excel和WPS表格中通过查找替换对单元格批量强制换行
  • 【C++】map 容器的使用
  • 论文阅读:Gorilla: Large Language Model Connected with Massive APIs
  • Python基础:PyMySQL
  • 音视频开发学习路线梳理(附 GitHub 仓库)
  • 达梦数据库-控制文件 (二)
  • FPGA开发流程
  • 一键搭建开发环境:制作bash shell脚本