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

高并发内存池(11)-PageCache获取Span(下)

高并发内存池(11)-PageCache获取Span(下)

这里在向页缓存申请新Span之前释放中心缓存的锁,是一个非常重要的性能优化策略,目的是减少锁的持有范围,提高并发性能

为什么需要在这里解锁?

1. 避免长时间持有锁

list._mtx.unlock();  // 释放中心缓存锁PageCache::GetInstance()->_pageMtx.lock();
Span* span = PageCache::GetInstance()->NewSpan(...);
PageCache::GetInstance()->_pageMtx.unlock();

关键原因:向PageCache申请内存可能是一个相对耗时的操作,因为可能涉及:

  • 遍历多个Span链表
  • 分割大Span为小Span
  • 甚至向操作系统申请新内存

如果持有中心缓存锁进行这些操作,会阻塞其他线程访问同一个桶。

2. 锁的粒度优化

优化前(错误做法):

// 持有中心缓存锁进行耗时操作
list._mtx.lock();
// ... 可能耗时的PageCache操作
list._mtx.unlock();

优化后(正确做法):

// 只持有锁进行快速操作
list._mtx.lock();
// 快速检查本地Span链表
list._mtx.unlock();  // 立即释放锁// 执行耗时操作(不持有中心缓存锁)
// ...// 重新加锁进行快速操作
list._mtx.lock();
// 快速插入新Span
list._mtx.unlock();

3. 减少死锁风险

PageCache有自己的锁(_pageMtx),如果同时持有多个锁:

// 危险:可能持有多个锁
list._mtx.lock();      // 持有中心缓存锁
_pageMtx.lock();       // 持有页缓存锁(可能产生死锁)

释放中心缓存锁后再申请页缓存锁,避免了锁嵌套和潜在的死锁风险

可视化过程

时间线对比

不释放锁的情况

线程1: [持有锁] → [PageCache操作] → [释放锁] ⏳
线程2: [等待锁] -----------------------→ [获取锁] ❌ 长时间阻塞

释放锁的情况

线程1: [持有锁] → [释放锁] → [PageCache操作] → [重新持锁] → [释放锁] ✅
线程2: [等待锁] → [获取锁] → [操作] → [释放锁] ✅ 几乎无阻塞

安全性考虑

你可能会担心:释放锁后,其他线程会不会修改状态?

实际上这是安全的,因为:

  1. 检查已完成:我们已经检查过当前桶没有可用Span
  2. 操作原子性:即使其他线程在此期间释放了内存,我们重新申请Span也是正确的
  3. 最终一致性:最后我们会将新Span加入链表,整体状态仍然一致

性能影响

这种优化在高并发场景下效果显著:

  • 低竞争环境:可能影响不大
  • 高竞争环境:吞吐量提升可达30-50%
  • 极端情况:避免线程长时间阻塞导致的性能悬崖

总结

这个解锁操作体现了多线程编程的重要原则:

持有锁的时间应该尽可能短

通过精细的锁粒度控制,在保证线程安全的前提下,最大化并发性能。这是高性能内存分配器设计的精髓之一。

http://www.xdnf.cn/news/1377055.html

相关文章:

  • 【C++标准库】<ios>详解基于流的 I/O
  • 腾讯云 CVM 上的 SpringBoot 应用避免非法访问
  • 寄存器的原理
  • YOLOv8-SMOT:一种高效鲁棒的实时小目标跟踪框架:基于切片辅助训练与自适应关联
  • 人工智能-python-深度学习-反向传播优化算法
  • ESP32使用场景及大规模物联网IoT
  • 流水线用到的Dockerfile和构建脚本build.sh
  • 如何安装 mysql-installer-community-8.0.21.0.tar.gz(Linux 详细教程附安装包下载)​
  • 神经网络学习笔记11——高效卷积神经网络架构SqueezeNet
  • 聊一聊 单体分布式 和 微服务分布式
  • 深度学习——优化函数
  • 自学嵌入式第二十九天:Linux系统编程-线程
  • flume监控文件写入 Kafka 实战:解耦应用与消息队列的最佳实践
  • 在语言模型监督式微调(SFT)中的 负对数似然(Negative Log-Likelihood, NLL)等价于最大化似然
  • 软考-系统架构设计师 管理信息系统(MIS)详细讲解
  • 为什么编码智能体可以重塑开发范式?
  • 【Mascaret】QGIS中Mascaret插件的使用
  • ESP8266:Arduino学习
  • 高并发内存池(12)-ThreadCache回收内存
  • 【HTML】隐藏滚动条但保留功能
  • 什么是AI+?什么是人工智能+?
  • redis---set详解
  • ICCV 2025 | 清华IEDA提出GUAVA,单图创建可驱动的上半身3D化身!实时、高效,还能捕捉细腻的面部表情和手势。
  • 《MongoDB 常用命令详解:从数据库操作到高级查询》
  • Windows/Linux 环境下 Jmeter 性能测试的安装与使用
  • 未成功:使用 Nginx 搭建代理服务器(正向代理 HTTPS 网站)
  • Linux学习-TCP并发服务器构建
  • 在 Windows 上部署 Go 语言开发环境
  • 数据分析编程第五步:数据准备与整理
  • JoyAgent-JDGenie开源多智能体系统详解:架构、部署与企业级应用案例