提示:高并发内存池完整项目代码,在主页专栏项目中

文章目录

提示:高并发内存池完整项目代码,在主页专栏项目中

先设计一个定长的内存池

一、为什么需要定长内存池?

🏢 传统内存分配的痛点

🏭 内存池的解决方案

二、定长内存池核心设计思想

1. 整体架构

2. 类定义解析

三、关键技术实现深度解析

1. 内存申请策略

2. 内存分配(New方法)

3. 内存释放(Delete方法)

四、空闲链表技术的巧妙运用

1. 链表存储原理

2. 内存对齐的重要性

五、性能优势分析

与传统malloc对比


先设计一个定长的内存池

       作为程序员(C/C++)我们知道申请内存使⽤的是malloc,malloc其实就是⼀个通⽤的⼤众货,什么场景 下都可以⽤,但是什么场景下都可以⽤就意味着什么场景下都不会有很⾼的性能,下⾯我们就先来设 计⼀个定⻓内存池做个开胃菜,当然这个定⻓内存池在我们后⾯的⾼并发内存池中也是有价值的,所 以学习他⽬的有两层,先熟悉⼀下简单内存池是如何控制的,第⼆他会作为我们后⾯内存池的⼀个基础组件。

#include <iostream>
#include <vector>
#include <time.h>
using std::cout;
using std::endl;#ifdef _WIN32#include<windows.h>
#else
// 
#endif// 定长内存池
//template<size_t N>
//class ObjectPool
//{};// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32void* ptr = VirtualAlloc(0, kpage<<13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else// linux下brk mmap等
#endifif (ptr == nullptr)throw std::bad_alloc();return ptr;
}template<class T>
class ObjectPool
{
public:T* New(){T* obj = nullptr;// 优先把还回来内存块对象,再次重复利用if (_freeList){void* next = *((void**)_freeList);obj = (T*)_freeList;_freeList = next;}else{// 剩余内存不够一个对象大小时,则重新开大块空间if (_remainBytes < sizeof(T)){_remainBytes = 128 * 1024;//_memory = (char*)malloc(_remainBytes);_memory = (char*)SystemAlloc(_remainBytes >> 13);if (_memory == nullptr){throw std::bad_alloc();}}obj = (T*)_memory;size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);_memory += objSize;_remainBytes -= objSize;}// 定位new,显示调用T的构造函数初始化new(obj)T;return obj;}void Delete(T* obj){// 显示调用析构函数清理对象obj->~T();// 头插*(void**)obj = _freeList;_freeList = obj;}private:char* _memory = nullptr; // 指向大块内存的指针size_t _remainBytes = 0; // 大块内存在切分过程中剩余字节数void* _freeList = nullptr; // 还回来过程中链接的自由链表的头指针
};

一、为什么需要定长内存池?

在C++开发中,频繁的内存分配和释放是性能瓶颈的主要来源之一。让我们先看一个现实中的比喻:

🏢 传统内存分配的痛点

想象每次需要办公桌时都现买:

  • ⏰ 时间开销大:每次都要去家具市场

  • 💰 成本高昂:中间商赚差价(内存碎片)

  • 🎯 效率低下:无法批量优化

🏭 内存池的解决方案

像大型办公室统一采购:

  • 🚀 批量获取:一次性申请大块内存

  • ⚡ 快速分配:直接从池中分配,无需系统调用

  • 🔄 重复利用:释放的内存放回池中复用

  • 📦 减少碎片:固定大小分配,无外部碎片

二、定长内存池核心设计思想

1. 整体架构

三大核心组件:

  • 🗃️ 大块内存:从系统申请的内存块

  • 🔗 空闲链表:管理已释放可重用的内存块

  • 📊 分配策略:决定如何分配新内存

2. 类定义解析

template<class T>
class ObjectPool
{
private:char* _memory = nullptr;     // 指向大块内存的指针size_t _remainBytes = 0;     // 剩余可用字节数void* _freeList = nullptr;   // 空闲链表头指针
};

三、关键技术实现深度解析

1. 内存申请策略

// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else// Linux下使用brk或mmap等系统调用
#endifif (ptr == nullptr)throw std::bad_alloc();return ptr;
}

设计要点:

  • 🖥️ 跨平台支持:Windows使用VirtualAlloc,Linux使用mmap

  • 📏 按页分配:以页面为单位(通常4KB),减少系统调用次数

  • 🚨 异常安全:分配失败抛出bad_alloc异常

2. 内存分配(New方法)

T* New()
{T* obj = nullptr;// 优先复用空闲链表中的内存块if (_freeList){void* next = *((void**)_freeList);  // 获取下一个空闲块obj = (T*)_freeList;                // 当前块作为分配对象_freeList = next;                   // 更新空闲链表头}else{// 剩余内存不足时申请新的大块内存if (_remainBytes < sizeof(T)){_remainBytes = 128 * 1024;  // 申请128KB_memory = (char*)SystemAlloc(_remainBytes >> 13); // 计算页数if (_memory == nullptr){throw std::bad_alloc();}}// 从大块内存中切分size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);obj = (T*)_memory;_memory += objSize;_remainBytes -= objSize;}// 定位new调用构造函数new(obj)T;return obj;
}

关键技术点:

  1. 空闲链表优先:先尝试从空闲链表获取已释放的内存

  2. 内存对齐:确保每个对象至少sizeof(void*)大小,便于链表操作

  3. 批量申请:一次性申请128KB内存,减少系统调用

  4. 定位new:在指定内存地址调用构造函数

3. 内存释放(Delete方法)

void Delete(T* obj)
{// 调用析构函数清理对象obj->~T();// 头插法将内存块加入空闲链表*(void**)obj = _freeList;_freeList = obj;
}

设计精髓:

  • 🧹 资源清理:显式调用析构函数

  • 🔗 链表管理:使用头插法将释放的内存加入空闲链表

  • ⚡ 高效复用:释放的内存立即可用于下次分配

四、空闲链表技术的巧妙运用

1. 链表存储原理

关键技巧: 利用内存块本身存储链表指针

 // 释放时:将当前内存块的前4/8字节存储下一个节点的地址
*(void**)obj = _freeList;  // 将_freeList值存入obj指向的内存
_freeList = obj;           // 更新链表头// 分配时:从链表头取出节点,并更新头指针
void* next = *((void**)_freeList);  // 读取下一个节点地址
obj = (T*)_freeList;                // 当前节点作为分配对象
_freeList = next;                   // 更新链表头

2. 内存对齐的重要性

size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);

为什么需要对齐?

  • 📏 最小大小:确保每个内存块至少能存储一个指针(4或8字节)

  • 🧩 地址对齐:保证指针操作的正确性

  • ⚡ 访问效率:对齐的内存访问速度更快

五、性能优势分析

与传统malloc对比

特性传统malloc定长内存池
分配速度较慢(系统调用)极快(直接操作内存)
内存碎片可能产生外部碎片无外部碎片
系统调用每次分配都可能调用批量申请,极少调用
线程安全需要加锁可设计为线程本地
适用场景通用分配固定大小对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/97909.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/97909.shtml
英文地址,请注明出处:http://en.pswp.cn/web/97909.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6-获取磁盘分区信息

观察文件 获取server端电脑里面存在哪些盘符 int MakeDriveInfo() { //1>A 2>B &#xff08;原本属于软盘的 &#xff09;3>C ... 26>Zstd::string result;for (int i 1; i < 26; i) { //让其循环if (_chdrive(i) 0) //改变当前的驱动,_chdrive函数(c和c中)应…

每天认识一个电子器件之LED灯

LED选型核心参数一览表参数类别关键参数说明 & 为什么重要基本电气参数正向电压 (Vf)LED正常发光时两端的电压降。必须匹配您的电路电压。红/黄光约1.8-2.2V&#xff0c;蓝/绿/白光约2.8-3.6V。正向电流 (If)LED正常发光时所需的电流。决定了LED的亮度&#xff0c;必须用电…

Spring Boot 集成 Flowable 7.1.0 完整教程

一、引言 在企业级应用开发中&#xff0c;工作流管理是不可或缺的一部分。从简单的请假审批到复杂的业务流程&#xff0c;工作流引擎能够显著提升系统的灵活性和可维护性。​​Flowable​​ 作为一个轻量级、基于 Java 的开源工作流引擎&#xff0c;完美支持 ​​BPMN 2.0​​…

uniapp离线打包安卓apk详细教程,从HbuilderX新建项目到Android Studio详细配置(一)

目录 一、基础离线打包&#xff0c;无引入模块&#xff0c;无原生插件 1. HbuilderX新建项目&#xff0c;开发者后台申请证书和离线key 2.HbuilderX生成本地包 二、Android Studio配置 1.下载离线SDK&#xff0c;解压&#xff0c;SDK版本需要和HbuilderX 版本一致&#xf…

蓝牙鼠标频繁卡顿?一招解决 Win10/11 的 USB 省电机制干扰问题

蓝牙鼠标频繁卡顿&#xff1f;一招解决 Win10/11 的 USB 省电机制干扰问题 问题背景 在使用蓝牙鼠标时&#xff0c;很多用户会遇到以下问题&#xff1a; 鼠标移动卡顿、延迟明显偶尔断连&#xff0c;需重新配对尤其在笔记本合盖或待机后恢复时更明显 这些问题在 Windows 10/11 …

领码方案|Spring Boot 异步请求深度剖析:从原理到 AI 驱动的吞吐量优化

摘要 本文以“领码方案”为核心&#xff0c;深入剖析 Spring Boot 异步请求的底层原理、线程模型、三种常用实现方式&#xff08;Callable、WebAsyncTask、DeferredResult&#xff09;的运行机制与性能特征&#xff0c;并结合 AI 驱动的自适应线程池调优、云原生架构下的弹性伸…

C++基础(13)——list类的模拟实现

目录 一、接口函数和类总览 二、节点结构体的实现 构造函数 三、迭代器结构体的实现 迭代器模版参数 构造函数 重载运算符 重载--运算符 重载运算符 重载*运算符 重载->运算符 四、list的模拟实现 默认成员函数 构造函数 拷贝构造函数 赋值运算符重载函数 …

从 APP 界面设计到用户体验优化:如何让你的应用脱颖而出?

作为一个经验丰富的设计师&#xff0c;在产品优化方面我踩过不少坑&#xff0c;也见过很多团队在界面设计和用户体验上的误区。APP 的外观决定了用户的第一印象&#xff0c;但能不能留住用户、让他们愿意持续使用&#xff0c;最终还是看体验。今天就结合自己的经验&#xff0c;…

Kafka如何配置生产者拦截器和消费者拦截器

Kafka 的生产者拦截器和消费者拦截器允许你在消息发送前后以及消息消费前后嵌入自定义逻辑&#xff0c;用于实现监控、审计、消息修改等功能。本文我们就用一个最常见的传递TraceId的案例来说明下这两类拦截器如何来使用。 生产者发送拦截器 生产者拦截器需要实现 org.apache.k…

vue表单弹窗最大化无法渲染复杂组件内容

背景&#xff1a;最大化后选然后复杂组件内容丢失&#xff0c;如下拉框、图片上传组件修复方案&#xff1a;使用深拷贝核心代码this.maximizeDialog {visible: true,title: 患者申请 - 最大化查看,formModel: JSON.parse(JSON.stringify(this.formModel || [])),formLogic: JS…

经典俄罗斯方块游戏 | 安卓三模式畅玩,暂时无广告!

大家好&#xff0c;今天想跟大家分享一款安卓版的俄罗斯方块游戏。适合无聊的时候玩玩&#xff0c;换换脑子&#xff0c;这款游戏太经典。80、90都玩过这个游戏。之前我也给大家推荐过一些离线小游戏&#xff0c;但有些用着用着就开始出现弹窗广告&#xff0c;这就有点烦&#…

今天开始学习新内容“服务集群与自动化”--crond服务、--syslog服务以及DHCP协议

一.crond简介1、基本介绍crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程&#xff0c;与windows下的计划任务类似&#xff0c;当安装完成操作系统后&#xff0c;默认会安装此服务工具&#xff0c;并且会自动启动crond进程&#xff0c;crond进程每分钟…

从go语言出发,搭建多语言云原生场景下全链路观测体系

一、方案背景 在公司内部devops平台的微服务化改造过程中&#xff0c;我们遇到了典型的分布式系统观测难题&#xff1a;服务间调用链路复杂、性能瓶颈难以定位、故障排查效率低下。特别是在生产环境出现问题时&#xff0c;往往需要花费大量时间在各个服务的日志中寻找蛛丝马迹。…

Vue 进阶实战:从待办清单到完整应用(路由 / 状态管理 / 性能优化全攻略)

Vue 进阶实战&#xff1a;从待办清单到完整应用&#xff08;路由 / 状态管理 / 性能优化全攻略&#xff09; 在上一篇博客里&#xff0c;我们一起实现了能本地存储的待办清单&#xff0c;不少朋友留言说&#xff1a;“学会了基础&#xff0c;但遇到‘登录后才能访问页面’‘多…

uniApp开发XR-Frame微信小程序 | 动态加载与删除模型

在使用xr-frame开发3D小程序时&#xff0c;我们经常需要根据需求去动态加载模型或删除模型&#xff0c;在官方的说明中&#xff0c;提到了相关方法&#xff0c;但并不太明确&#xff0c;也没有确切的实例。 我们先来看一下官方给出的说明。 一. Shadow元素 我们需要用代码动…

把多个 PPT 合并在一起,三步告别复制粘贴

制作部门汇报分册、项目阶段文件等工作需要将多个零散的PPT合并为一份完整文档。手动复制粘贴不仅效率低下&#xff0c;还容易导致格式错乱、动画丢失。本文介绍一种高效方法&#xff0c;三步操作即可将多个PPT文件快速合并为单一文档。无论是整合汇报材料&#xff0c;还是准备…

安卓旋转屏幕后如何防止数据丢失-ViewModel入门

Android ViewModel 入门教程 在日常开发中&#xff0c;当 Activity 因为旋转屏幕或内存回收被销毁重建时&#xff0c;UI 中的数据也会丢失。 这时候&#xff0c;Android Jetpack 提供的 ViewModel 就能帮我们解决这个问题。 1. 什么是 ViewModel ViewModel 是一种架构组件。它专…

Linux 下的 Vim 使用与网络安全配置详解

目录 引言 一、Vim 编辑器的使用 1. Vim 的模式 2. 常用操作命令 3. 保存与退出 4. 多窗口与 Shell 切换 二、Linux 网络基础 1. 网络分类 2. IP 地址与分类 三、网络配置与工具 1. ifconfig 2. netstat 3. wget 4. 主机名与 IP 映射 四、Linux 防火墙与安全设置…

Docker 容器传输文件的常用方法

Docker 容器传输文件的常用方法 在 Docker 日常使用中&#xff0c;经常需要在主机与容器之间传输文件&#xff08;如配置文件、代码包、日志等&#xff09;。以下是四种最常用的实现方式&#xff0c;覆盖临时传输、持久共享、构建集成等不同场景。 1. 使用 docker cp 命令&…

视频转音频在线工具大比拼,哪家体验更胜一筹?

最近工作上遇到了个挺有意思的需求&#xff0c;需要从几个教学视频里提取出音频内容&#xff0c;方便做成播客形式&#xff0c;让学员能随时随地学习。一开始&#xff0c;我以为这活儿挺简单的&#xff0c;不就是把视频里的声音单独弄出来嘛&#xff0c;结果一上手才发现&#…