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

C++初阶:C/C++内存管理

一.C/C++内存分布

先来回顾一下C语言内存分区示意图如下:

代码区:

  • 程序执行代码一般存放在代码区,字符串常量以及define定义的常量也可能存放在代码区。

常量区:

  •  字符串,数字等常量以及const修饰的全局变量往往存放在常量区。

全局(静态)区:

  • 将全局变量和静态变量存放在全局(静态)区:已初始化的全局变量和静态变量存放在一块区域, 未初始化的全局变量和未初始化的静态变量存放在相邻的另一块区域。

堆区:

  • 堆区由程序员调用malloc, calloc, realloc等分配函数进行内存空间的分配和释放,按内存地址由低地址到高地址增长。

栈区:

  • 栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理;在函数执行时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

我们再来看下面的一段代码和相关问题 :

int globalVar = 1;//数据段/静态区
static int staticGlobalVar = 1;//数据段/静态区
void Test()
{static int staticVar = 1;//数据段/静态区int localVar = 1;//栈区int num1[10] = { 1, 2, 3, 4 };//栈区char char2[] = "abcd";//char2存放在栈区,*char2代表字符串第一个元素存放在栈区const char* pChar3 = "abcd";//pChar3存放在栈区,*pChar3存放在常量区int* ptr1 = (int*)malloc(sizeof(int) * 4);//ptr1是个指针存放在栈区,*ptr1指向的内容存放在堆区int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}

小结:

说明:

  1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的;
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信;
  3. 堆用于程序运行时动态内存分配,堆是可以上增长的;
  4. 数据段--存储全局数据和静态数据;
  5. 代码段--可执行的代码/只读常量。

二.C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

2.1.new/delete操作内置类型

new运算符

new运算符用来申请一块连续的内存,其格式如下:

new 数据类型 (初始化列表);

malloc()函数申请内存时返回的是一个void*类型的指针,而new与malloc()不同,它分配一块存储空间并且指定了类型信息,并根据初始化列表中给出的值进行初始化,是直接可以使用的内存,这个过程称之为new一个对象。 而且new动态创建对象时不必为该对象命名,直接指定数据类型即可。如果申请内存成功,返回一个类型指针;如果申请内存失败,则返回NULL。

用new可以创建基本数据类型对象,也可以创建数组对象,其格式如下:

new 数据类型 [数组长度];

使用new创建数组时,后面可以加小括号(),但括号中不可以指定任何初始值,加小括号时由编译器为其提供默认初始值,而不加小括号时不提供任何初始值。例如:

int* pi=new int[10]();//pi所指向的数组中10个元素初始化为0
char* pc=new char[10];//pc所指向的数组中没有提供初始值

C++虽然不允许定义长度为0的数组变量,但明确指出,调用new创建长度为0的数组是合法的,它返回有效的非零指针,但该指针不能进行有效的解引用操作,因为它没有指向任何元素,它主要的作用是用于比较运算。例如:

double *pd=new double[0];

delete运算符

用new运算符分配内存,使用后要及时释放以免造成内存泄漏,C++提供了delete运算符来释放new出来的内存空间,其格式如下:

delete 指针名;

直接作用于指针就可以删除由new创建的对象,释放指针所指向的内存空间。但在释放数组对象时要在指针名前加上[ ],其格式如下:

delete [] 指针名;

如果缺失[ ],编译器在编译时不会报错,但delete只能释放部分空间,因此在程序运行时会出现内存泄漏等问题。

int main()
{int* p1 = new int;//不会初始化:动态申请一个int类型的空间int* p3 = new int(10);//会初始化:申请一个int类型的空间,初始化为10int* p4 = new int[10];//申请10个int的数组,不会初始化int* p5 = new int[10]{ 1,2,3,4 };//会初始化delete p1;delete p3;delete [] p4;delete [] p5;//C语言版//int* p2 = (int*)malloc(sizeof(int));//if (p2 == nullptr)//{//	perror("malloc fail");//}return 0;
}

调试分析:

注意:

申请和释放单个元素的空间,使用new和delete操作符;申请和释放连续的空间,使用new[]和delete[],要匹配起来使用。

2.2.new/delete操作自定义类型

new/delete除了可以操作内置类型,也可以操作自定义类型。

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//注意:不加缺省值会报错,提示:没有合适的默认构造函数可用/*A(int a): _a(a){cout << "A():" << this << endl;}*/~A(){cout << "~A():" << this << endl;}private:int _a;
};
//
//匹配使用,不要交叉,否则结果是不确定的,malloc出来的就要用free释放,new出来的就要用delete释放,不要混淆了
int main()
{//new/delete 和 malloc/free 最大区别是 new/delete对于【自定义类型】除了开辟空间还会调用构造函数和析构函数A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);//调用构造函数free(p1);delete p2;//调用析构函数// 内置类型几乎是一样的int* p3 = (int*)malloc(sizeof(int)); // Cint* p4 = new int;free(p3);delete p4;A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];//调用10次构造函数free(p5);delete[] p6;//调用10次析构函数return 0;
}

运行结果:

注意:

要匹配使用,不要交叉,否则结果是不确定的,malloc出来的就要用free释放,new出来的就要用delete释放,不要混淆。

三.operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。如下所示:

//operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果该应对措施用户设置了,则继续申请,否则抛异常。
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0){if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}}return (p);
}//operator delete: 该函数最终是通过free来释放空间的
void operator delete(void* pUserData)
{_CrtMemBlockHeader* pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);  /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg(pUserData, pHead->nBlockUse);__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}

案例:

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//注意:不加缺省值会报错,提示:没有合适的默认构造函数可用/*A(int a): _a(a){cout << "A():" << this << endl;}*/~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{A* a = new A(1);delete a;return 0;
}

反汇编分析:

小结:

通过上述两个全局函数的实现知道,operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的。

提问:

既然operator new和operator delete这两个全局函数是用malloc和free实现的,那我们是否可以用operator new和operator delete来实现malloc和free的功能? 

答案:可以。

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//注意:不加缺省值会报错,提示:没有合适的默认构造函数可用/*A(int a): _a(a){cout << "A():" << this << endl;}*/~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{//内置类型int* p1 = (int*)operator new(sizeof(int));int* p2 = new int;operator delete(p1);delete p2;//自定义类型A* p3 = (A*)operator new(sizeof(A));//不会调用构造函数A* p4 = new A(1);operator delete(p3);//不会调用析构函数delete p4;return 0;
}

四.new和delete的实现原理

内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似。不同的地方是:new/delete申请和释放的是单个元素的空间,new[ ]和delete[ ]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

int main()
{//内置类型//失败了抛出异常//int* p1 = (int*)operator new(sizeof(int));int* p1 = new int;//失败了返回空int* p2 = (int*)malloc(sizeof(int*));if (p2 == nullptr){perror("malloc fail");}return 0;
}

自定义类型

new的原理:

  1. 调用operator new函数申请空间;
  2. 在申请的空间上执行构造函数,完成对象的构造。

delete的原理:

  1. 在空间上执行析构函数,完成对象中资源的清理工作;
  2. 调用operator delete函数释放对象的空间。

new T[N]的原理:

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请;
  2. 在申请的空间上执行N次构造函数。

delete[]的原理:

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理;
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。

案例一: 自定义类型

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{//自定义类型//申请空间:operator new -> 封装malloc//调用构造函数A* p5 = new A;//先调用析构函数//再operator delete p5指向的空间delete p5;//申请空间:operator new[] -> operator new -> 封装malloc//调用10次构造函数A* p6 = new A[10];//先调用10次析构函数//再operator delete[] p6指向的空间delete[] p6;A* p9 = new A[10];//free(p9);//delete p9;//把自定义的析构函数屏蔽掉,则不会调用析构函数,可以运行通过,此时的编译器也不会去多开辟4个字节的空间来存放元素个数10delete[] p9;//vs编译器会多开4个字节的空间存放个数10,return 0;
}

解析:

案例二:自定义类型不匹配问题

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};class Stack
{
public:Stack(){cout << "Stack()" << endl;_a = new int[4];_top = 0;_capacity = 4;}~Stack(){delete[] _a;_top = _capacity = 0;}private:int* _a;int _top;int _capacity;
};int main()
{//内置类型不匹配通常不会报错int* p7 = new int[10];free(p7);//自定义类型不匹配A* p8 = new A;//free(p8);//少调用析构函数,但由于不涉及内存申请,通常不会报错delete p8;Stack st;//st存放在栈上,为12字节,其中存放了_a等,通过调用构造函数为_a开辟了16字节的内存空间,并指向了这块空间Stack* pst = new Stack;//pst存放在栈上,为指针占4个字节,new时会去堆上开辟12个字节的空间存放_a等,通过调用构造函数为_a开辟了16字节的内存空间,并指向了这块空间//free(pst);//少调用析构函数,但由于涉及内存申请,导致内存泄漏,但不会报错delete pst;//先调用析构函数释放_a所指向的内存空间(16字节),再调用operator delete(pst)释放new时在堆上开辟12个字节的空间//结论//由于 new/delete 底层实现机制有关联交叉。不匹配使用时,可能有问题,可能没问题,建议大家一定匹配使用return 0;
}

解析:

五.定位new表达式(placement-new)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

使用格式:

new (place_address) type或者new (place_address) type(initializer-list)

注意:place_address必须是一个指针,initializer-list是类型的初始化列表。

使用场景:

定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{A aa;//p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行A* p1 = (A*)malloc(sizeof(A));if (p1 == nullptr){perror("malloc fail");}//对一块已有空间初始化--定位new//new(p1)A;//注意:如果A类的构造函数有参数时,此处需要传参new(p1)A(1);p1->~A();free(p1);A* p2 = (A*)operator new(sizeof(A));new(p2)A(10);p2->~A();operator delete(p2);return 0;
}

六.malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:它们都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  1. malloc和free是函数,new和delete是操作符;
  2. malloc申请的空间不会初始化,new可以初始化;
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[ ]中指定对象个数即可;
  4. malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型;
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常;
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。 

七.内存泄漏

什么是内存泄漏,内存泄漏有什么危害?

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

相关文章:

C++初阶:C/C++内存管理

一.C/C内存分布 先来回顾一下C语言内存分区示意图如下&#xff1a; 代码区&#xff1a; 程序执行代码一般存放在代码区&#xff0c;字符串常量以及define定义的常量也可能存放在代码区。 常量区&#xff1a; 字符串&#xff0c;数字等常量以及const修饰的全局变量往往存放在…...

新成果展示:AlGaN/GaN基紫外光电晶体管的设计与制备

紫外光电探测器被广泛应用于导弹预警、火灾探测、非可见光通信、环境监测等民事和军事领域&#xff0c;这些应用场景的实现需要器件具有高信噪比和高灵敏度。因此&#xff0c;光电探测器需要具备响应度高、响应速度快和暗电流低的特性。近期&#xff0c;天津赛米卡尔科技有限公…...

Ivs+keepalived:高可用集群

Ivskeepalived:高可用集群 keepalived为lvs应运而生的高可用服务。lvs的调度器无法做高可用&#xff0c;keepalived这个软件就是为了实现调度器的高可用。 注意&#xff1a;keepalived不是专门为lvs集群服务的&#xff0c;也可以做其他代理服务器的高可用。 lvs的高可用集群&a…...

win10安装spark

一、进入spark下载页面 连接 Downloads | Apache Spark 二、解压下载后的.tgz文件 直接解压即可 三、运行 运行bin目录下的 spark-shell.cmd 提示 Did not find winutils.exe: java.io.FileNotFoundException: java.io.FileNotFoundException: HADOOP_HOME and hadoop.hom…...

基于Spring Boot 的毕业生实习就业管理系统(绿色)

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring Boot 的毕业生实习就业管理系…...

1600*C. Remove Adjacent(贪心字符串)

Problem - 1321C - Codeforces 解析&#xff1a; 贪心&#xff0c;从z到a遍历&#xff0c;每次循环减去符合题意的字符。 #include<bits/stdc.h> using namespace std; signed main(){int n;string s;cin>>n>>s;for(char iz;i>a;i--){for(int j0;j<s.…...

CRC校验码2018-架构师(六十一)

以下关于串行总线的说法中&#xff0c;正确的是&#xff08;&#xff09;。 串行总线一般都是双全工总线&#xff0c;适宜于长距离传输数据串行总线传输的波特率是总线初始化时预先定义好的&#xff0c;使用中不可改变串行总线是按位&#xff08;BIT&#xff09;传输数据的&am…...

CSS设置超出范围滚动条和滚动条样式

CSS设置超出范围滚动条和滚动条样式 效果展示 当块级内容区域超出块级元素范围的时候&#xff0c;就会以滚动条的形式展示&#xff0c;你可以滚动里面的内容&#xff0c;里面的内容不会超出块级区域范围。 未设置超出隐藏&#xff0c;显示滚动条 超出隐藏&#xff0c;显示滚动…...

EtherCAT从站转CclinkIE协议网关应用案例

远创智控的YC-ECT-CCLKIE网关&#xff0c;一款具有强大功能的ETHERCAT通讯网关。 它可以将ETHERCAT网络和CCLINK IE FIELD BASIC网络无缝连接起来。作为ETHERCAT总线中的从站&#xff0c;本网关可以接收来自ETHERCAT主站的数据&#xff0c;并将其传输到CCLINK IE FIELD BASIC网…...

腾讯云 AI 绘画:文生图、图生图、图审图 快速入门

腾讯云 AI 绘画是腾讯云推出的一款基于人工智能的图像生成和编辑产品&#xff0c;能够根据输入的图片或描述文本&#xff0c;智能生成与输入内容相关的图片&#xff0c;支持多样化的图片风格选择。 在本文中&#xff0c;我们将介绍如何使用腾讯云 AI 绘画的三项主要功能&#…...

前端项目中,强缓存和协商缓存的配置

前端缓存分为HTTP缓存和浏览器缓存 HTTP缓存(本文重点) 强缓存协商缓存 浏览器缓存 比较熟悉的 cookie&#xff0c;localstorage sessionstorage indexDB…或者cacheStorage 请求的缓存&#xff0c;如果本地有取本地的 这里主要笔记http缓存 先说总结的内容 webpack配置&am…...

【LeetCode】2. 两数相加

题目链接 文章目录 Python3方法&#xff1a; 模拟 ⟮ O ( n ) 、 O ( 1 ) ⟯ \lgroup O(n)、O(1)\rgroup ⟮O(n)、O(1)⟯ C Python3 方法&#xff1a; 模拟 ⟮ O ( n ) 、 O ( 1 ) ⟯ \lgroup O(n)、O(1)\rgroup ⟮O(n)、O(1)⟯ # Definition for singly-linked list. # cl…...

springBoot与Vue共同搭建webSocket环境

欢迎使用Markdown编辑器 你好&#xff01; 这片文章将教会你从后端springCloud到前端VueEleementAdmin如何搭建Websocket 前端 1. 创建websocket的配置文件在utils文件夹下websocket.js // 暴露自定义websocket对象 export const socket {// 后台请求路径url: ,websocketCo…...

【Python】collections.Counter

Python内置模块collections中的Counter是字典子类。Counter不是字典&#xff0c;但很像字典。 Counter具有字典的键和值&#xff0c;键是各个元素&#xff0c;值为该元素出现的次数。 Counter相当于计数器。常用于哈希映射&#xff08;哈希表&#xff09;。 from collection…...

【Elasticsearch】es脚本编程使用详解

目录 一、es脚本语言介绍 1.1 什么是es脚本 1.2 es脚本支持的语言 1.3 es脚本语言特点 1.4 es脚本使用场景 二、环境准备 2.1 docker搭建es过程 2.1.1 拉取es镜像 2.1.2 启动容器 2.1.3 配置es参数 2.1.4 重启es容器并访问 2.2 docker搭建kibana过程 2.2.1 拉取ki…...

Synchronized 关键字

在Java中&#xff0c;线程同步使用最多的方法是使用synchronized关键字。每个Java对象都隐含有一把锁&#xff0c;这里称为Java内置锁(或者对象锁、隐式锁)。使用synchronized(syncObject)调用相当于获取 syncObject 的内置锁&#xff0c;所以可以使用内置锁对临界区代码段进行…...

Maven系列第8篇:大型Maven项目,快速按需任意构建

本篇涉及到的内容属于神技能&#xff0c;多数使用maven的人都经常想要的一种功能&#xff0c;但是大多数人都不知道如何使用&#xff0c;废话不多说&#xff0c;上干货。 需求背景 我们需要做一个电商项目&#xff0c;一般都会做成微服务的形式&#xff0c;按业务进行划分&am…...

卷积神经网络(CNN)的组成结构以及其优点

卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;简称CNN&#xff09;是一种深度学习模型&#xff0c;主要用于处理具有网格结构的数据&#xff0c;如图像和视频。它的结构包含以下几个关键组件&#xff1a; 卷积层&#xff08;Convolutional Layer&#xff…...

[③ADRV902x]: Digital Filter Configuration(接收端)

前言 本篇博客主要总结了ADRV9029 Rx接收端链路中各个滤波器的配置。配置不同的滤波器系数以及不同的参数&#xff0c;可以对输入的数字信号灵活得做decimation处理&#xff0c;decimation信号抽取&#xff0c;就是降低信号采样率的过程。 Receiver Signal Path 下图为接收端…...

企业安全—DevSecOps概述详情

0x00 前言 SDL存在的问题在于体量过于庞大&#xff0c;不利于快速进行适配和进行&#xff0c;所以就有了DevSecOps&#xff0c;实际上是因为敏捷开发也就是DevOps的推进&#xff0c;并且坐上了云服务模式的火车&#xff0c;所以这一系列的东西都开始普及。DevSecOps作为DevOps…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...