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

C++项目——高并发内存池(2)——thread_cache的基础功能实现

1.并发内存池concurrent memory pool

组成部分

thread cache、central cache、page cache

  • thread cache:线程缓存是每个线程独有的,用于小于64k的内存的分配,线程从这里申请内存不需要加锁,每个线程独享一个cache,这也就是这个并发线程池高效的地方。
  • central cache:中心缓存是所有线程所共享,thread cache是按需从central cache中获取的对象。central cache周期性的回收thread cache中的对象,避免一个线程占用了太多的内存,而其他线程的内存吃紧。达到内存分配在多个线程中更均衡的按需调度的目的。central cache是存在竞争的,所以从这里取内存对象是需要加锁,但只会在两个及以上thread cache同时内存不够时,才会发生竞争。
  • page cache:页缓存是在central cache缓存上面的一层缓存,存储的内存是以页为单位存储及分配的,central cache没有内存对象时,从page cache分配出一定数量的page,并切割成定长大小的小块内存,分配给central cache。page cache会回收central cache满足条件的span对象,并且合并相邻的页,组成更大的页,缓解内存碎片的问题。

2.thread cache

thread cache是哈希桶结构,每个桶是一个按桶位置映射大小的内存块对象的自由链表,即每一个桶都是一个定长内存池。C++项目——高并发内存池(1)--介绍及定长内存池_Gosolo!的博客-CSDN博客

每个线程都有一个thread cache对象,所以每个线程在这里获取对象和释放对象是无锁的。

 

 既然是哈希桶,那映射关系如何确定呢?

2.1 计算对象大小的对齐映射规则

首先进行内存拆分,每个thread cache总共享有64kb的缓存池

[1,128] 8byte对齐 freelist[0,16)

[128+1,1024] 16byte对齐 freelist[16,72)

[1024+1,8*1024] 128byte对齐 freelist[72,128)

[8*1024+1,64*1024] 1024byte对齐 freelist[128,184)

[64*1024+1,256*1024] 8*1024byte对齐 freelist[184,208) 这个不是给thread cache用的

那也就是说,根据我申请空间的大小不同,我们使用不同的桶来给予内存。

申请空间在[1,128],我们8个字节8个字节的给。

申请空间在[128+1,1024],16个字节16个字节的给。

所以当申请内存时,需要计算给他几个内存小块,即对齐数。

2.1.1 确认分配的内存空间

class SizeClass
{
public:   //按照申请的内存大小 决定分配多少对齐数整数倍的内存空间static size_t _RoundUp(size_t size, size_t alignNum){size_t alignSize;if (size % alignNum != 0){alignSize = (size / alignNum + 1)*alignNum;}else{alignSize = size;}return alignSize;}static inline size_t RoundUp(size_t size){if (size <= 128){return _RoundUp(size, 8);}else if (size <= 1024){return _RoundUp(size, 16);}else if (size <= 8 * 1024){return _RoundUp(size, 128);}else if (size <= 64 * 1024){return _RoundUp(size, 1024);}else if (size <= 256 * 1024){return _RoundUp(size, 8 * 1024);}else{assert(false);return -1;}}
};

更好的一种写法

	static inline size_t _RoundUp(size_t bytes, size_t alignNum){return ((bytes + alignNum - 1) & ~(alignNum - 1));}

2.1.2 确定哈希桶编号

简单写法

	size_t _Index(size_t bytes, size_t alignNum){//假如需要8字节 那他在下标为0的桶if (bytes % alignNum == 0){return bytes / alignNum - 1;}else//假如需要8字节 那他在下标为0的桶{    return bytes / alignNum;}}

 利用位运算的高效方法

class SizeClass
{
public:static inline size_t _Index(size_t bytes, size_t align_shift){return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;}// 计算映射的哪一个自由链表桶static inline size_t Index(size_t bytes){assert(bytes <= MAX_BYTES);// 每个区间有多少个链static int group_array[4] = { 16, 56, 56, 56 };if (bytes <= 128){return _Index(bytes, 3);}else if (bytes <= 1024){return _Index(bytes - 128, 4) + group_array[0];}else if (bytes <= 8 * 1024){return _Index(bytes - 1024, 7) + group_array[1] + group_array[0];}else if (bytes <= 64 * 1024){return _Index(bytes - 8 * 1024, 10) + group_array[2] + group_array[1] + group_array[0];}else if (bytes <= 256 * 1024){return _Index(bytes - 64 * 1024, 13) + group_array[3] + group_array[2] + group_array[1] + group_array[0];}else{assert(false);}return -1;}};

2.2 thread cache框架

class ThreadCache
{
public:// 申请和释放内存对象void* Allocate(size_t size);void Deallocate(void* ptr, size_t size);/************************************本文先实现申请和释放对象************************************/// 从中心缓存获取对象void* FetchFromCentralCache(size_t index, size_t size);// 释放对象时,链表过长时,回收内存回到中心缓存void ListTooLong(FreeList* list, size_t size);
private:FreeList _freeLists[NFREELISTS];
};
/*TLS thread lcoal storage 为了使线程从thread cache 里申请内存不加锁 就需要一个仅自己可见,其他线程不可见的变量存储方式
*/
static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;

2.2.1 TLS

TLS介绍转载自

Thread Local Storage_evilswords的博客-CSDN博客

Instance(单件)机制原本是让代码执行时只有一个实例,但有的时候又希望每个线程各自能有自己的"单件"相互不影响,处理类似的需求最先想到的就是全局表,然后按线程id或是管理线程的key索引到对应的单件上,取全局表的时候需要加锁。 虽然这样也能实现目的,但是代码看上去很不自然。最近发现还是有更自然的方法能实现这一点,就是 TLS 线程本地存储。

static void* ConcurrentAlloc(size_t size)
{// 通过TLS 每个线程无锁的获取自己的专属的ThreadCache对象if (pTLSThreadCache == nullptr){pTLSThreadCache = new ThreadCache;}cout << std::this_thread::get_id() << ":" << pTLSThreadCache << endl;return pTLSThreadCache->Allocate(size);
}static void ConcurrentFree(void* ptr, size_t size)
{assert(pTLSThreadCache);pTLSThreadCache->Deallocate(ptr, size);
}

2.2.2 thread cache具体实现

void* ThreadCache::Allocate(size_t size)
{assert(size<= MAX_BYTES);size_t alignSize = SizeClass::RoundUp(size);size_t index = SizeClass::Index(size);if (!_freeLists[index].Empty()){return _freeLists[index].Pop();}else{return FetchFromCentralCache(index, alignSize);}
}
void ThreadCache::Deallocate(void* ptr, size_t size)
{assert(ptr);assert(size <= MAX_BYTES);size_t index = SizeClass::Index(size);_freeLists[index].Push(ptr);}

2.2.3 流程图

 

相关文章:

C++项目——高并发内存池(2)——thread_cache的基础功能实现

1.并发内存池concurrent memory pool 组成部分 thread cache、central cache、page cache thread cache&#xff1a;线程缓存是每个线程独有的&#xff0c;用于小于64k的内存的分配&#xff0c;线程从这里申请内存不需要加锁&#xff0c;每个线程独享一个cache&#xff0c;这…...

【C进阶】数据的存储

文章目录:star:1. 数据类型:star:2. 整形在内存中的存储2.1 存储规则2.2 存储模式2.3 验证大小端模式:star:3. 数据范围3.1 整形溢出3.2 数据范围的求解3.3 练习:star:4. 浮点型在内存中的存储4.1 浮点数的存储规则4.2 练习5. :star::star:总结(思维导图)⭐️1. 数据类型 在了…...

【已解决】异常断电文件损坏clickhouse启动不了:filesystem error Structure needs cleaning

问题 办公室有一台二手服务器&#xff0c;作为平时开发测试使用。由于机器没放在机房&#xff0c;会偶发断电异常断电后&#xff0c;文件系统是有出问题的可能的&#xff0c;尤其是一些不断在读写合并的文件春节后&#xff0c;发现clickhouse启动不了&#xff0c;使用systemct…...

FlinkSQL行级权限解决方案及源码

FlinkSQL的行级权限解决方案及源码&#xff0c;支持面向用户级别的行级数据访问控制&#xff0c;即特定用户只能访问授权过的行&#xff0c;隐藏未授权的行数据。此方案是实时领域Flink的解决方案&#xff0c;类似离线数仓Hive中Ranger Row-level Filter方案。 源码地址: https…...

【基础篇】8 # 递归:如何避免出现堆栈溢出呢?

说明 【数据结构与算法之美】专栏学习笔记 什么是递归&#xff1f; 递归是一种应用非常广泛的算法&#xff08;或者编程技巧&#xff09;&#xff0c;比如 DFS 深度优先搜索、前中后序二叉树遍历等等都是用到了递归。 方法或函数调用自身的方式称为递归调用&#xff0c;调用…...

基于微信公众号(服务号)实现扫码自动登录系统功能

微信提供了两种方法都可以实现扫描登录。 一种是基于微信公众平台的扫码登录&#xff0c;另一种是基于微信开放平台的扫码登录。 两者的区别: 微信开放平台需要企业认证才能注册&#xff08;认证费用300元&#xff0c;只需要认证1次&#xff0c;后续不再需要进行缴费年审&#…...

AXI实战(二)-跟着产品手册设计AXI-Lite外设(AXI-Lite转串口实现)

AXI实战(二)-跟着产品手册设计AXI-Lite 设(AXI-Lite转串口实现) 看完在本文后,你将可能拥有: 一个AXI_Lite转串口的从端(Slave)设计使用SV仿真AXI-Lite总线的完整体验实现如何在读通道中实现"等待"小何的AXI实战系列开更了,以下是初定的大纲安排: 欢迎感兴趣的…...

一周搞定模拟电路视频教程,拒绝讲PPT,仿真软件配合教学,真正一周搞定

目录1、灵魂拷问2、懦夫救星3、福利领取2、使用流程1、灵魂拷问 问&#xff1a;模拟电路很难吗&#xff1f; 答&#xff1a;嗯&#xff0c;真的很难&#xff01;&#xff01;&#xff01; 问&#xff1a;模拟电路容易学吗&#xff1f; 答&#xff1a;很难学&#xff0c;建议放…...

高德地图获得角度

//传入两个经纬度点得到车辆角度 设置车辆Marker角度 getAngle(startPoint, endPoint) {if (!(startPoint && endPoint)) {return 0;}let dRotateAngle Math.atan2(Math.abs(startPoint.lng - endPoint.lng),Math.abs(startPoint.lat - endPoint.lat));console.log(&q…...

【C++】-- C++11基础常用知识点(下)

上篇&#xff1a; 【C】-- C11基础常用知识点&#xff08;上&#xff09;_川入的博客-CSDN博客 目录 新的类功能 默认成员函数 可变参数模板 可变参数 可变参数模板 empalce lambda表达式 C98中的一个例子 lambda表达式 lambda表达式语法 捕获列表 lambda表达底层 …...

提到数字化,你想到哪些关键词

我们的生活中已经充满了数据&#xff0c;各种岗位例如运营、市场、营销上也都喜欢在职位要求加上一条利用数据、亦或是懂得数据分析。事实上&#xff0c;数据已经成为了构建现代社会的基本生产要素&#xff0c;并且因为不受自然环境的限制&#xff0c;已经成为了人们对未来社会…...

【蓝桥杯集训·每日一题】AcWing 1249. 亲戚

文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴并查集一、题目 1、原题链接 1249. 亲戚 2、题目描述 或许你并不知道&#xff0c;你的某个朋友是你的亲戚。 他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。 如果…...

iphone所有机型的屏幕尺寸

手机设备型号屏幕尺寸(吋)分辨率点数(pt)屏幕显示模式分辨率像素(px)屏幕比例iPhone SE4.03205682x640113616:9iPhone 6/6s/7/8/SE 24.73756672x750133416:9iPhone 6P/7P/8P5.54147363x1242220816:9iPhone XR/116.14148962x828179219.5:9iPhone X/XS/11P5.83758123x1125243619.…...

Windows10使用-处理IE自动跳转至Edge

文章目录 前言一、调整Edge二、调整Internet选项三、搜索栏的恢复总结前言 微软官方宣布,自2023年2月14日永久停止支持Internet Explorer 11浏览器。后期点击IE 图标将会自动跳转到Edge界面。对于一些网站,可能需要使用IE模式才能正常使用,这时候就需要做相应的调整,才能够…...

linux input子系统,gpio-keys,gpio中断使用

GPIO控制 嵌入式linux下应用编程会经常使用到gpio&#xff0c;GPIO 可以通过 sysfs 方式进行操控&#xff0c;进入到/sys/class/gpio 目录下&#xff0c;如下所示&#xff1a; 可以看到该目录下包含两个文件 export、 unexport 以及 5 个 gpiochipX&#xff08;X 等于 0、 32、…...

分析称勒索攻击在非洲、中东与中国增长最快

Orange Cyberdefense&#xff08;OCD&#xff09;于 2022 年 12 月 1 日发布了最新的网络威胁年度报告。报告中指出&#xff0c;网络勒索仍然是头号威胁 &#xff0c;也逐渐泛滥到世界各地。 报告中的网络威胁指的是企业网络中的某些资产被包括勒索软件在内的攻击进行勒索&…...

ArcPy批量合并矢量shape文件

当有大量矢量&#xff08;.shp&#xff09;格式文件需要合并成一个矢量文件时&#xff0c;可以考虑使用 ArcPy 进行批量合并&#xff0c;代码如下&#xff1a; # coding:utf-8 import os import arcpy from arcpy import envenv.workspace "C:/Users/Desktop/demo"…...

改写有序表的题目核心点

1、核心点 1&#xff09;分析增加什么数据项可以支持题目 2&#xff09;有序表一定要保持内部参与排序的key不重复 【补充说明&#xff1a;要存储重复的key值&#xff0c;要么将相同的key压在一起&#xff0c;要么将每个key再封装一层&#xff0c;用内存地址区分】 3&#…...

收藏这几个开源管理系统做项目,领导看了直呼牛X!

项目SCUI Admin 中后台前端解决方案Vue .NetCore 前后端分离的快速发开框架next-admin 适配移动端、pc的后台模板django-vue-admin-pro 快速开发平台Admin.NET 通用管理平台RuoYi 若依权限管理系统Vue3.2 Element-Plus 后台管理框架Pig RABC权限管理系统zheng 分布式敏捷开发…...

【刷题篇】链表(下)

前言&#x1f338;各位读者们好&#xff0c;本期我们来填填之前留下的坑&#xff0c;继续来讲解几道和链表相关的OJ题。但和上期单向链表不一样的是&#xff0c;我们今天的题目主要是于环形链表有关&#xff0c;下面让我们一起看看吧。&#x1f4bb;本期的题目有&#xff1a;环…...

Shiro

Shiro 1.权限管理概述 2.Shiro权限框架   2.1 概念   2.2 Apache Shiro 与Spring Security区别 3.Shiro认证   3.1 基于ini认证   3.2 自定义Realm --认证 4.Shiro授权   4.1 基于ini授权   4.2 自定义realm – 授权 5.项目集成shiro 认证-授权注意点   5.1 认证…...

使用nginx进行负载均衡配置详细说明

使用nginx进行负载均衡 1. nginx负载均衡介绍 nginx应用场景之一就是负载均衡。在访问量较多的时候&#xff0c;可以通过负载均衡&#xff0c;将多个请求分摊到多台服务器上&#xff0c;相当于把一台服务器需要承担的负载量交给多台服务器处理&#xff0c;进而提高系统的吞吐…...

N皇后问题

#include<iostream> #include<string> #include<vector> using namespace std; #define MAX 20//最大20个皇后 int n ;//实际皇后个数 int sum ;//答案个数 vector<vector<int>> attack(MAX, vector<int>(MAX, 0));//标记攻击位置 vector&…...

强化学习DQN之俄罗斯方块

强化学习DQN之俄罗斯方块强化学习DQN之俄罗斯方块算法流程文件目录结构模型结构游戏环境训练代码测试代码结果展示强化学习DQN之俄罗斯方块 算法流程 本项目目的是训练一个基于深度强化学习的俄罗斯方块。具体来说&#xff0c;这个代码通过以下步骤实现训练&#xff1a; 首先…...

1.3总线:并行总线、串行总线、单工、半双工、全双工、总线宽度、总线带宽、总线的分类、数据总线、地址总线、控制总线

1.3总线&#xff1a;并行总线、串行总线、单工、半双工、全双工、总线宽度、总线带宽、总线的分类、数据总线、地址总线、控制总线总线并行总线、串行总线单工、半双工、全双工总线宽度总线带宽总线的分类数据总线&#xff08;Data Bus&#xff0c;DB&#xff09;地址总线&…...

Linux驱动开发—设备树开发详解

设备树开发详解 设备树概念 Device Tree是一种描述硬件的数据结构&#xff0c;以便于操作系统的内核可以管理和使用这些硬件&#xff0c;包括CPU或CPU&#xff0c;内存&#xff0c;总线和其他一些外设。 Linux内核从3.x版本之后开始支持使用设备树&#xff0c;可以实现驱动代…...

深入浅出C++ ——继承

文章目录一、继承的相关概念1. 继承的概念2. 继承格式3. 继承方式4. 访问限定符5. 继承基类成员访问方式的变化二、基类和派生类对象赋值转换三、继承中的作用域四、派生类的默认成员函数五、继承与友元六、继承与静态成员七、菱形继承及菱形虚拟继承1. 单继承2. 多继承3. 菱形…...

设计模式C++实现20: 桥接模式(Bridge)

部分内容参考大话设计模式第22章&#xff1b;本实验通过C语言实现。 一 基本原理 意图&#xff1a;将抽象部分和实现部分分离&#xff0c;使它们都可以独立变化。 上下文&#xff1a;某些类型由于自身的逻辑&#xff0c;具有两个或多个维度的变化。如何应对“多维度的变化”…...

Android中的Rxjava

要使用Rxjava首先要导入两个包&#xff0c;其中rxandroid是rxjava在android中的扩展 implementation io.reactivex:rxandroid:1.2.1implementation io.reactivex:rxjava:1.2.0observer 是一个观察者接口&#xff0c;泛型T为观察者观察数据的类型&#xff0c;里面只有三个方法&a…...

【RocketMQ】源码详解:消息储存服务加载、文件恢复、异常恢复

消息储存服务加载 入口:org.apache.rocketmq.store.DefaultMessageStore#load 在创建brokerContriller时会调用初始化方法初始化brokerController,在初始化方法中会进行消息储存服务的加载 this.messageStore.load(); 加载方法主要是加载一些必要的参数和数据&#xff0c;如配…...