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

C++——内存池_2

C++内存池

  • 重载 new 和 delete 运算符
  • C++内存池
    • 使用内存池的目的
    • 逐步实现内存池

重载 new 和 delete 运算符

实际开发中,重载newdelete的主要目的是实现内存池。内存池在高性能的服务程序中很常用。点击浏览重载 new 和 delete 运算符的内容,建议先看这部分。

C++内存池

内存池预先分配内存空间。程序启动的时候,先向系统申请一大块连续的空间。在程序中,如果需要用内存, 从内存池中借一块小的空间出来,用完了再还回去。说白了,如果沒有内存池,直接向系统借;如果有内存池,就向内存池借。
程序在运行的过程中,如果内存池太小了,可以扩展。但有一个原则,每次都会向系统申请一大块连续的内存空间。

使用内存池的目的

目的主要有两个:

  1. 提升分配和归还的速度
  • 对高性能的服务程序来说,频繁的new和delete也算浪费资源。
  1. 减少内存碎片
  • 碎片多了,系统管理内存的效率就会下降,系统的性能也会下降。

逐步实现内存池

#include <iostream>using namespace std;class Car
{public:int speed;float acceleration;Car(int sp, float acc){speed = sp, acceleration = acc; cout << "~~ 类的构造 speed: " << speed << " acceleration: " << acceleration << " ~~" << endl;}~Car() {cout << "~~ 调用析构 ~~" << endl;}
};int main() {Car* p = new Car(320, 4.6);cout << "p的地址:" << p << "\nspeed: " << p->speed << " acceleration: " << p->acceleration << endl;delete p;return 0;
}

在上面这段代码中,Car类有两个类型分别是intfloat的成员变量,所以,用Car类创建的对象占用的内存空间是8字节。
我打算预先向系统申请连续的18字节的内存空间,如下图:
内存示意图
也就是说,内存池的大小是18字节。
组织数据的方法是:标志位,1个字节(图中的0号、9号字节),表示后面的空间是否被占用。后面8个(1~8号、10~17号)字节刚好可以存放1个Car类对象。
标志位的取值只有010表示空闲,1表示占用。故这18个字节的内存池,能存放2个Car对象。
当需要为Car对象分配内存的时候,先判断标志位是否被占用,若没有被占用,就把标志位后面的这个内存地址返回。
了解以上这些知识后,来看一段示例代码:

#include <iostream>using namespace std;class Car
{public:int speed;float acceleration;Car(int sp, float acc){speed = sp, acceleration = acc; cout << "~~ 类的构造 speed: " << speed << " acceleration: " << acceleration << " ~~" << endl;}~Car() {cout << "~~ 调用析构 ~~" << endl;}void* operator new(size_t size){cout << "调用类的重载 new: " << size << " 字节" << endl;void* ptr = malloc(size);cout << "申请的地址是:" << ptr << endl;return ptr;}void operator delete(void* ptr){cout << "调用了类的重载 delete" << endl;if (ptr == 0) return;free(ptr);}
};int main() {Car* p = new Car(320, 4.6);cout << "p的地址:" << p << "\nspeed: " << p->speed << " acceleration: " << p->acceleration << endl;delete p;return 0;
}

上面这段代码在C++——内存池_1也用到了,现在在此基础上实现简单的内存池。

首先,内存池需要一个指针来存放它的起始地址。内存池就是一块内存,没有数据类型的说法,用什么类型的指针都可以。在此示例中,用字符更合适,因为字符指针+1就是偏移1个字节。

  • 声明指针,用于存放内存池的起始地址;
  • 定义初始化内存池的函数;
  • 定义释放内存池的函数

接下来修改分配内存的重载函数void* operator new(size_t size),向内存池中申请内存。池中只有2个位置,判断标志位,哪个空闲就返回哪一块。如果没有空闲维位置,可以返回空地址,也可以直接向系统申请内存。
修改申请内存的重载函数,释放内存的函数void operator delete(void* ptr)也一并在下方给出,代码如下:

#include <iostream>
#include <cstring>using namespace std;class Car
{public:int speed;float acceleration;static char* m_pool; // 内存池的起始地址(为什么是静态变量?后面有提到)static bool initpool() // 初始化内存池的函数{m_pool = (char*)malloc(18); // 向系统申请18字节的内存if (m_pool == 0) return false; // 若申请失败,返回 falsememset(m_pool, 0, 18); // 把内存池中的内容初始化为 0cout << "内存池的起始地址:" << (void*)m_pool << endl;return true;}static void freepool() // 释放内存池的函数{if(m_pool == 0) return; // 如果内存池为空,无需释放,直接返回free(m_pool); // 把内存池归还给系统cout << "内存池已释放" << endl;}Car(int sp, float acc){speed = sp, acceleration = acc; cout << "~~ 类的构造 speed: " << speed << " acceleration: " << acceleration << " ~~" << endl;}~Car() {cout << "~~ 调用析构 ~~" << endl;}// 类的静态成员函数 static 所以要把 m_pool 声明为静态变量 初始化函数和释放函数也要声明为 static// C++——内存池_1 这篇文章的最后有讲到这个点void* operator new(size_t size){if(m_pool[0] == 0) // 判断第一位是否空闲 也就是要看内存空间 m_pool 的第一位的标志位 m_pool[0] 是否等于 0{cout << "分配了第一块内存:" << (void*)(m_pool + 1) << endl;m_pool[0] = 1; // 把第一位置标记为已分配return m_pool + 1; // 返回第一个用于存放对象的地址}if(m_pool[9] == 0) // 判断第二位是否空闲{cout << "分配了第二块内存:" << (void*)(m_pool + 10) << endl;m_pool[9] = 1; // 把第一位置标记为已分配return m_pool + 10; // 返回第一个用于存放对象的地址}// 若两个位置都不可用,就直接向系统申请内存void* ptr = malloc(size); // 向系统申请内存cout << "向系统申请到的内存地址:" << ptr << endl;return ptr;}void operator delete(void* ptr){if(ptr == 0) return; // 若传进来的地址为空,直接返回。if(ptr == m_pool + 1) // 若传进来的地址是内存池的第一个位置{cout << "释放第一块内存!" << endl;m_pool[0] = 0; // 把第一个位置标记为空闲return; // 归还内存之后,函数应该立即返回}if(ptr == m_pool + 10) {cout << "释放第二块内存!" << endl;m_pool[9] = 0; // 把第二个位置标记为空闲return; // 归还内存之后,函数应该立即返回}// 若传进来的地址不属于内存池,把它归还系统。free(ptr); // 释放内存}
};// 内存池的指针 m_pool 是静态成员变量,需要在 main 函数外面初始化。
char* Car::m_pool = 0; // 初始化内存池指针int main() {if(Car::initpool() == false) {cout << "初始化内存池失败!!!" << endl; return -1;}Car* p1 = new Car(320, 4.6);cout << "p1的地址:" << p1 << "\nspeed: " << p1->speed << " acceleration: " << p1->acceleration << endl;Car* p2 = new Car(220, 4.0);cout << "p2的地址:" << p2 << "\nspeed: " << p2->speed << " acceleration: " << p2->acceleration << endl;Car* p3 = new Car(520, 2.9);cout << "p3的地址:" << p3 << "\nspeed: " << p3->speed << " acceleration: " << p3->acceleration << endl;delete p1;Car* p4 = new Car(420, 4.4);cout << "p4的地址:" << p4 << "\nspeed: " << p4->speed << " acceleration: " << p4->acceleration << endl;delete p2;delete p3;delete p4;Car::freepool(); // 释放内存池return 0;
}

如果内存池用完了,根据业务的需求,一般有三种方法:

  • 扩展内存
  • 直接向系统申请内存
  • 返回空地址

编译运行,效果应该如下(地址是你PC上开辟的内存地址,与我的不同):

内存池的起始地址:0x56366e051eb0
分配了第一块内存:0x56366e051eb1
~~ 类的构造 speed: 320 acceleration: 4.6 ~~
p1的地址:0x56366e051eb1
speed: 320 acceleration: 4.6
分配了第二块内存:0x56366e051eba
~~ 类的构造 speed: 220 acceleration: 4 ~~
p2的地址:0x56366e051eba
speed: 220 acceleration: 4
向系统申请到的内存地址:0x56366e052ee0
~~ 类的构造 speed: 520 acceleration: 2.9 ~~
p3的地址:0x56366e052ee0
speed: 520 acceleration: 2.9
~~ 调用析构 ~~
释放第一块内存!
分配了第一块内存:0x56366e051eb1
~~ 类的构造 speed: 420 acceleration: 4.4 ~~
p4的地址:0x56366e051eb1
speed: 420 acceleration: 4.4
~~ 调用析构 ~~
释放第二块内存!
~~ 调用析构 ~~
~~ 调用析构 ~~
释放第一块内存!
内存池已释放

感谢浏览,一起学习!

相关文章:

C++——内存池_2

C内存池 重载 new 和 delete 运算符C内存池使用内存池的目的逐步实现内存池 重载 new 和 delete 运算符 实际开发中&#xff0c;重载new和delete的主要目的是实现内存池。内存池在高性能的服务程序中很常用。点击浏览重载 new 和 delete 运算符的内容&#xff0c;建议先看这部…...

如何使用PHP爬虫获取店铺详情:一篇详尽指南

在数字化时代&#xff0c;数据的价值不言而喻。对于企业来说&#xff0c;获取竞争对手的店铺详情、顾客评价等信息对于市场分析和决策至关重要。PHP作为一种广泛使用的服务器端脚本语言&#xff0c;结合其强大的库支持&#xff0c;使得编写爬虫程序变得简单而高效。本文将详细介…...

HTML5和CSS3新增特性

HTML5的新特性 HTML5新增的语义化标签 HTML5 的新增特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题&#xff0c;基本是 IE9 以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量…...

linux运行vue编译后的项目

如果你的 Vue 项目使用了 history 模式&#xff08;而非默认的 hash 模式&#xff09;&#xff0c;在纯静态服务器中会出现类似的问题。因为 Vue Router 的 history 模式要求所有未匹配的路径都重定向到 index.html&#xff0c;以便 Vue 前端处理路径。 首先在本地执行npm run…...

论文阅读:A Software Platform for Manipulating theCamera Imaging Pipeline

论文代码开源链接&#xff1a; A Software Platform for Manipulating the Camera Imaging Pipelinehttps://karaimer.github.io/camera-pipeline/摘要&#xff1a;论文提出了一个Pipline软件平台&#xff0c;可以方便地访问相机成像Pipline的每个阶段。该软件允许修改单个模块…...

【MySQL篇】持久化和非持久化统计信息的深度剖析(第一篇,总共六篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…...

Ubuntu下安装Qt

1.如图1所示&#xff0c;在Index of /archive上下载安装包&#xff1b; 图1 2.将图1安装包下载好之后&#xff0c;通过共享文件夹的方式拷贝到ubutntu&#xff0c;如图2所示&#xff1b; 图2 3.如图3所示&#xff0c;执行chmod x qt-creator-opensource-linux-x86_64-10.0.2.…...

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL&#xff08;丹摩智算&#xff09; 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…...

数据库(总结自小林coding)|索引失效的场景、慢查询、原因及如何优化?undo log、redo log、binlog 作用、MySQL和Redis的区别

数据库&#xff08;总结自小林coding&#xff09;|索引失效的场景、慢查询、原因及如何优化&#xff1f;undo log、redo log、binlog 作用、MySQL和Redis的区别 说一下索引失效的场景&#xff1f;什么是慢查询&#xff1f;原因是什么&#xff1f;可以怎么优化&#xff1f;undo …...

Docker容器运行CentOS镜像,执行yum命令提示“Failed to set locale, defaulting to C.UTF-8”

最近对运维比较感兴趣&#xff0c;以前虽然对公司负责的项目做过运维工作&#xff0c;但用的都是最原始的方法&#xff0c;例如是在阿里云服务器上直接安装jdk&#xff0c;tomcat,redis ,nginx 。这种方式对不大的项目还能够支持&#xff0c;随着项目变大&#xff0c;服务增加&…...

OpenCV基本图像处理操作(六)——直方图与模版匹配

直方图 cv2.calcHist(images,channels,mask,histSize,ranges) images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的…...

【LLM学习笔记】第四篇:模型压缩方法——量化、剪枝、蒸馏、分解

文章目录 1. 为什么要进行模型压缩2. 模型量化2.1 常见数据类型2.2 浮点数表示2.3 线性量化2.4 非线性量化2.5 挑战2.6 实际应用 3. 模型剪枝4. 模型蒸馏4.1 模型蒸馏的基本流程4.2 模型蒸馏的优势4.3 实际应用 5. 低秩分解&#xff08;低秩近似&#xff09;5.1 基本概念5.2 实…...

python3 自动更新的缓存类

这个类会在后台自动更新缓存数据&#xff0c;你只需要调用方法来获取数据即可。 自动更新缓存类 以下是 AutoUpdatingCache 类的实现&#xff1a; import threading import timeclass AutoUpdatingCache:def __init__(self, update_function, expiry_time60):""&qu…...

英语知识网站开发:Spring Boot框架应用

3系统分析 3.1可行性分析 通过对本英语知识应用网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本英语知识应用网站采用SSM框架&#xff0c;JAVA作为开发语…...

文件上传upload-labs-docker通关

&#xff08;图片加载不出&#xff0c;说明被和谐了&#xff09; 项目一&#xff1a; sqlsec/ggctf-upload - Docker Image | Docker Hub 学习过程中,可以对照源码进行白盒分析. 补充&#xff1a;环境搭建在Linux虚拟机上的同时&#xff0c;以另一台Windows虚拟机进行测试最…...

git(Linux)

1.git 三板斧 基本准备工作&#xff1a; 把远端仓库拉拉取到本地了 .git --> 本地仓库 git在提交的时候&#xff0c;只会提交变化的部分 就可以在当前目录下新增代码了 test.c 并没有被仓库管理起来 怎么添加&#xff1f; 1.1 git add test.c 也不算完全添加到仓库里面&…...

Doris实战—构建日志存储与分析平台

构建日志存储与分析平台 日志是系统运行的详细记录,包含各种事件发生的主体、时间、位置、内容等关键信息。出于运维可观测、网络安全监控及业务分析等多重需求,企业通常需要将分散的日志采集起来,进行集中存储、查询和分析,以进一步从日志数据里挖掘出有价值的内容。 针…...

【vue3+Typescript】unapp+stompsj模式下替代plus-websocket的封装模块

由于plus-websocket实测存在消息丢失的问题&#xff0c;只能寻找替代的方案&#xff0c;看文章说使用原生的即可很好的工作。而目前在stompjs里需要使用websocket类型的封装模块&#xff0c;看了下原来提供的接口&#xff0c;采用uniapp原生的websocket模式&#xff0c;对原模块…...

Tcon技术和Tconless技术介绍

文章目录 TCON技术&#xff08;传统时序控制器&#xff09;定义&#xff1a;主要功能&#xff1a;优点&#xff1a;缺点&#xff1a; TCONless技术&#xff08;无独立时序控制器&#xff09;定义&#xff1a;工作原理&#xff1a;优点&#xff1a;缺点&#xff1a; TCON与TCONl…...

C#-利用反射自动绑定请求标志类和具体执行命令类

文章速览 概述例程请求类命名空间父类示例子类示例 命令类命名空间子类示例 记录的数据结构实现绑定方法 坚持记录实属不易&#xff0c;希望友善多金的码友能够随手点一个赞。 共同创建氛围更加良好的开发者社区&#xff01; 谢谢~ 概述 需求&#xff1a; 将指定的两种类型的…...

高中数学练习:初探均值换元法

文章目录 1. 均值换元法定义2. 均值换元法优点3. 均值换元法应用4. 均值换元法示例4.1 求解分式方程4.2 求解指数方程4.3 计算最大值 5. 实战小结 1. 均值换元法定义 均值换元法是一种数学技巧&#xff0c;通过引入新变量 t t t将两个变量 x x x和 y y y表示为它们的平均值加上…...

数据结构单链表,顺序表,广义表,多重链表,堆栈的学习

单链表 比如一个多项式&#xff0c;主要包括x的系数&#xff0c;x的指数&#xff0c;那么可以创建一个一维数组来存储它的系数和指数&#xff0c;用数组下标来表示。它的系数可以用数组下标对应的数组元素来储存。 可是这样储存会浪费空间所以采用单链表形式来存储。 即创建一…...

【保姆级教程】使用lora微调LLM并在truthfulQA数据集评估(Part 2.在truthfulQA上评估LLM)

上一期我们成功用lora微调了一个模型传送门&#xff0c;怎样评估模型呢&#xff1f;目前LLM没有一个统一的BENCHMARK。我们今天选用truthfulQA。 truthfulQA数据集格式如下所示 {question: What is the smallest country in the world that is at least one square mile in ar…...

thinkphp中对请求封装

请求的封装 //调用 $res Http::post($this->baseUrl . $url,$params,[CURLOPT_HTTPHEADER > [Content-Type: application/json,Content-Length: . strlen($params),],]);<?php namespace fast; /*** 字符串类*/ class Http {/*** 发送一个POST请求*/public static …...

leetcode hot100【LeetCode 215.数组中的第K个最大元素】java实现

LeetCode 215.数组中的第K个最大元素 题目描述 给定一个整数数组 nums 和一个整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;要求排名是从大到小的&#xff0c;因此第 k 个最大元素是排序后的第 k 个元素。你需要设计一个高效的算法来解决这个问题。…...

簡單易懂:如何在Windows系統中修改IP地址?

無論是為了連接到一個新的網路&#xff0c;還是為了解決網路連接問題&#xff0c;修改IP地址都是一個常見的操作。本文將詳細介紹如何在Windows系統中修改IP地址&#xff0c;包括靜態IP地址的設置和動態IP地址的獲取。 IP地址是什麼&#xff1f; IP地址是互聯網協議地址的簡稱…...

Python中的23种设计模式:详细分类与总结

设计模式是解决特定问题的通用方法&#xff0c;分为创建型模式、结构型模式和行为型模式三大类。以下是对每种模式的详细介绍&#xff0c;包括其核心思想、应用场景和优缺点。 一、创建型模式&#xff08;Creational Patterns&#xff09; 创建型模式关注对象的创建&#xff0…...

日历使用及汉化——fullcalendar前端

官网 FullCalendar - JavaScript Event Calendar 引入项目 <link hrefhttps://cdnjs.cloudflare.com/ajax/libs/fullcalendar/5.10.1/main.min.css relstylesheet /><script srchttps://cdnjs.cloudflare.com/ajax/libs/fullcalendar/5.10.1/main.min.js></sc…...

视频截断,使用 FFmpeg

使用 FFmpeg 截取视频并去掉 5 分 49 秒后的内容&#xff0c;可以使用以下命令&#xff1a; ffmpeg -i input.mp4 -t 00:05:49 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k output.mp4-i input.mp4&#xff1a; 指定输入视频文件 input.mp4。 -t 00:05:49&#x…...

使用系统内NCCL环境重新编译Pytorch

intro&#xff1a; 费了老大劲,来重新编译pytorch&#xff0c;中间报了无数错误。原生的编译好的pytorch是直接用的其自带NCCL库&#xff0c;并且从外部是不能进行插桩的&#xff0c;因为根本找不到libnccl.so文件。下面记录下重新编译pytorch的过程。指定USE_SYSTEM_NCCL1。这…...

网站运营专员是干嘛的/怎么让客户主动找你

下面的这些经典的引言来自英文&#xff0c;也许有些我翻译的是不很好&#xff0c;所以&#xff0c;我提供了中英对照&#xff0c;如果有问题&#xff0c;请大家指正。 过早的优化是万恶之源。Premature optimization is the root of all evil!- Donald Knuth 在水里行走和以一个…...

网站规划包括哪些内容/怎么在线上推广自己的产品

SVD—matlab,python,scikit-learn 操作对比1.简介SVD的用途有两个&#xff0c;第一个是降噪&#xff0c;第二个是pca主成分分析&#xff0c;但每个包和语言都有不同的方法&#xff0c;所以在这里一一总结2.matlab机器学习实战方法x[1,1,1,0,0;2,2,2,0,0;1,1,1,0,0;5,5,5,0,0;1,…...

石门县建设局网站/谷歌应用商店

文章目录前言一、现象二、原因三、解决步骤四、示例五、参考前言 在你的iOS团队中&#xff0c;如果在使用持续集成来完成自动化打包分发的工作&#xff0c;你可能会了解如何使用一些命令行工具来构建ipa文件&#xff0c;其中一款使用较为广泛的是xcodebuild。 在我们的团队中…...

哪些网站需要备案/怎么在百度发广告

采购单位&#xff1a;天津市房地产经济技术信息中心拟采购的内容&#xff1a;序号 型号 描述 数量 1 Oracle应用服务器套件软件 WebLogic Suite Processor 2cpu 2 Oracle数据同步检测软件 Oracle GoldenGate Veridata Processor 2cpu 3 Oracle数据同步核心软件 O…...

服装鞋帽 网站建设/章鱼磁力链接引擎

二进制日志&#xff08;bin-log日志&#xff09;bin-log作用&#xff1a;bin-log日志记录了所有的DDL和DML的语句&#xff0c;但不包括查询的语句&#xff0c;语句以事件的方式保存&#xff0c;描述了数据的更改过程&#xff0c;此日志对发生灾难时数据恢复起到了极为重要的作用…...

动易网站默认密码/如何进行网络营销

昨日&#xff0c;台湾南海岸一带发生了7.1级地震。这次地震损坏了亚太 2号国际海底光缆 (APCN2) 。一时间&#xff0c;无数与国际网络通讯有关的业务&#xff0c;都经历了致命的堵塞。现代人类对科技的依赖&#xff0c;再一次遭到自然的嘲弄。不提这事对大洋两岸人们带来的诸多…...