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

【C++】深入解析C/C++内存管理:new与delete的使用及原理

在这里插入图片描述

C++语法相关知识点可以通过点击以下链接进行学习一起加油!
命名空间缺省参数与函数重载C++相关特性类和对象-上篇类和对象-中篇
类和对象-下篇日期类

本章将分享C++为何放弃malloc/free系列,选择新系列new/delete去管理内存。深度探索new/delete的使用及其原理,malloc/free系列与new/delete系列的不同之处。

请添加图片描述
Alt
🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记
🌈初阶数据结构笔记专栏: 初阶数据结构笔记
🌈Linux笔记专栏: Linux笔记

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 请添加图片描述

文章目录

  • 一、C/C++中程序内存区域划分
    • 1.1 相关练习测试
  • 二、C语言中动态内存管理方式
  • 三、C++内存管理方式
    • 3.1 使用new/delete进行数据操作
      • 3.1.1 new/delete 操作内置类型
      • 3.1.2 new和delete操作自定义类型
  • 四、 new和delete原理及其两个全局函数的实现(operator new/operator delerte)
  • 五、深入了解new和delete工作原理
  • 六、malloc/free系列和new/delete系列的区别
  • 七、delete最好匹配使用
  • 八、定位new表达式(placement -new)(了解)
  • 九、内存泄漏(了解)
    • 9.1 内存泄漏概念
    • 9.2 内存泄漏的危害
    • 9.3 内存泄漏分类

一、C/C++中程序内存区域划分

在这里插入图片描述

内存区域相关作用:

  • 栈又叫堆栈:非静态局部变量、函数参数、返回值等等,栈是向下增长的

  • 内存映射段时高效的I/O映射方式,用于装载一个共享的动态内存库,用户可以使用系统接口创建共享共享内存,做进程间通信

  • 堆用于程序运行时动态内存分配,堆时可以上增长的

  • 数据段:存储全局数据和静态数据

  • 代码段:可执行的代码、只读常量

在语法上将数据段称为静态区、代码段称为常量区,而以上操作系统的命名。

提出相关思考:

  1. 为什么要分不同的区域
  2. 哪个区域是我们需要重点关注的

回答:

  1. 根据对象不同的生命周期和作用域,分配到不同的区域中,统一管理,高效地对对象进行处理
  2. 堆是我们要需要重点关注的,这是系统留给我们控制的内存,其他系统是自动的

1.1 相关练习测试

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";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}

在这里插入图片描述

答案:

  • 选择题:C、C、C、A、A 。A、A、A、D、A、B

  • 填空题:40、5、4、4/8、4、4/8

这里容易混洗的char str1[] ="abcd"const char* str2 ="abcd"。这里str1是个数组将常量拷贝到数组,而str2是直接指向常量区中常量。

在这里插入图片描述

二、C语言中动态内存管理方式

C语言中,系统通过一系列函数赋予了我们对堆上空间的控制

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);free(p3 );
}

提出思考:

  1. malloc/calloc/realloc的区别是什么?

  2. 这里使用realloc是否还需要free(p2)

  3. malloc的实现原理?

第一个问题的回答:

对于malloc/calloc/realloc是系统为我们提供在堆上申请空间的途径。在功能上大体是相同的,对于malloccalloc这两个函数,除了参数部分及其是否完成初始化,其他功能是相同的。

relloc比较特别,属于扩容时使用的函数。扩容有两种方式:原地扩容和异地扩容。如果realloc第一个参数部分为空,可以当作malloc使用)。具体还是参考下这篇博客有详细解释内存管理

第二个问题的回答:

由于realloc进行了扩容操作。如果是原地扩容,在原来开辟空间上完成扩容操作,这里p3会同p2指向这块空间,只需要free(p3);如果是异地扩容,将p2空间中数据拷贝一份,在堆上找一块空间充足地方,完成扩容和拷贝操作,p2指向原空间,会被系统自动收回,不需要对p2进行free操作。对此无论是原地还是异地,只需要free(p3)即可

第三个问题的回答:

可以通过该链接进行学习GLibc堆利用入门

三、C++内存管理方式

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

3.1 使用new/delete进行数据操作

3.1.1 new/delete 操作内置类型

int main()
{//动态申请一个int类型的空间int* ptr1 = new int;//动态申请一个int类型的空间并且初始化为10int* ptr2 = new int(10);//动态申请10个int类型的空间int* ptr3 = new int[3];//动态申请10个int类型的空间并且完成初始化int* ptr4 = new int[10]{ 1,2,3 };//剩下没有明确给值,默认为0delete ptr1;delete ptr2;delete []ptr3;delete[]ptr4;return 0;
}

在这里插入图片描述

注意需要匹配使用new和delete操作符:

  • 申请和释放单个元素的空间:new、delete
  • 申请和释放多个元素的空间:new[]、delete[]

3.1.2 new和delete操作自定义类型

class A
{
public:A(int a = 0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{//自定义类型A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;//内置类型int* p3 = (int*)malloc(sizeof(int));int* p4 = new int;free(p3);delete p4;//开辟连续自定义类型空间A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}

在这里插入图片描述

从结果上来看,对于newmalloc最大差别在于对自定义类型除了开辟空间以外,还会调用构造函数和析构函数及其进行良好的初始化和控制。对于malloc而言无法对自定义类型进行好的初始化和控制,只负责开辟内存,除此之外内置类型几乎相同(初始化不同)

对于new优于malloc的几点:

  1. 用法上进行调正,更简洁好用
  2. 可以控制初始化
  3. 对于自定义类型,new可以开空间+构造函数
  4. new配合构造函数,可以更加便捷创建节点等
  5. new失败了以后抛异常,不需要手动检查

第一点:

	int* p0 = (int*)malloc(sizeof(int));int* p1 = new int;

第二点:

	int* p2 = new int[10];int* p3 = new int(10);int* p4 = new int[10]{ 1,2,3 };

第三点

struct ListNode
{ListNode* _next;int _val;ListNode(int val):_val(val),_next(nullptr){}
};
//创建不带哨兵位,同时如果是插入数据,new ListNode(3)即可
ListNode* CreateList(int n)
{ListNode head(-1);ListNode* tail = &head;int val;printf("请依次输入%d个节点的值:>", n);for (size_t i = 0; i < n; i++){cin >> val;tail->_next = new ListNode(val);tail = tail->_next;}return head._next;
}

第四点:

void func()
{int n = 1;while (1){int* p = new int[1024 * 1024*100];cout <<n<<"->"<< p << endl;++n;}
}
int main()   
{try{func();}catch (const exception& e){cout << e.what() << endl;}return 0;
}

在这里插入图片描述

这里try和catch就是捕捉异常,这一点到后面有涉及。以上种种都是new的优点,所以我们不推荐再使用malloc/free系列。

四、 new和delete原理及其两个全局函数的实现(operator new/operator delerte)

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new再底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间(operator new与operator delete不是对new和delete的重载)

	int* p1 = (int*)operator new(10 * 4);//int* p1=new int(10*4)operator delete(p1);//delete(p1)

从代码中可以看出来,new/delete和operator new/operator delete效果上是相同的。那么直接使用new/delete就行,operator new/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)//通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果//malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施//就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。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;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

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

内置类型:

如果申请的是内置类型的空间,new/malloc与delete/free基本类似,不同的地方是new在申请空间失败时会抛异常,malloc会返回NULL

自定义类型:

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来释放空间

通过汇编,深入立即其中

在这里插入图片描述

对于自定义类型转换指令只有两个核心动作调用全局函数及其构造或析构,而内置类型只有调用全局函数。

对此可得:

  • operator new是对malloc的封装,如果失败抛异常,实现new
  • operator newp[]封装operator new,最终还是malloc
  • operator delete对free的封装
  • operator delete[]封装operator delete

在这里插入图片描述

在这里插入图片描述

同时这里需要注意调用顺序上的问题

五、深入了解new和delete工作原理

new是个操作符,在编译时new A会转化为汇编指令调用malloc,一般来说malloc失败会返回空,由于C++是面向对象的过程,malloc失败返回空是不太合适,一般采用抛异常。全局函数operator new来封装malloc,去调正失败的返回情况

在这里插入图片描述

int main()
{A* p1 = new A;//operator new+1次构造A* p2 = new A[10];//operatorn new[]+10构造int* p3=new int[10];//operator new[](占用40个字节)delete p1;//1次析构+operator deletedelete[] p2;//?次析构+operator deletedelete[] p3;//operator deletereturn 0;
}

结合汇编和代码提供的信息,提出以下问题:

  1. 编译器如何开始确定所需开辟空间大小
  2. 为什么p2指向大小为44字节空间,而不是40字节空间
  3. 为什么编译器知道p2需要调用10次析构函数

回答:

  1. 由于new属于操作符,在编译时就计算出了所需空间的大小。
  2. 编译器在所开辟空间位置前面,也是调用operator new函数多开四个字节,用于记录对象个数(针对自定义类型)
  3. 由于内置类型不需要调用析构函数,对此不需要记录对象个数,而自定义类型需要记录对象个数。delete[]需要通过对象个数才知道调用多少次析构函数。如果将析构函数注释,p2占用空间为40字节。由于编译器会自动生成析构函数,而该析构函数没有发挥占用,编译器会优化导致不需要四个字节记录对象个数,具体需要看编译器是否优化

六、malloc/free系列和new/delete系列的区别

我们将通过用法和底层特性两点说明:

共同点:

  • 都是从堆上申请空间,并且需要用户手动释放

不同点:

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

七、delete最好匹配使用

在这里插入图片描述

解析说明:图中delete没有匹配使用,导致可能报错。这里p2指向并不是申请空间的第一个位置,第一个位置是operator new[]实现存放对象个数申请的空间。由于空间是不能一块块释放,对此p2释放的位置是错误的,并且不明确需要调用多少次析构函数,可能会造成内存泄漏。如果是delete[] p2,会将p2指针偏移前面四个字节。

但是以上种种情况,导致这个问题是否报错,具体需要看编译器是否进行优化(编译器是否调用析构函数),对此我们只需要正确的使用delete就行,上面只是了解就行了

八、定位new表达式(placement -new)(了解)

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

new(指针->空间)类型() :显式调用构造函数对已经有的空间初始化

构造函数不能显式调用,析构可以显式调用(一般不会去调用两次析构的)

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

一般没有人会使用,因为这里就是把new分成两部分,那么干嘛不直接使用new更加方便。

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

C++基本放弃了malloc/free系列。关于realloc扩容解决措施,在C++相关容器中它们会自动处理内存的扩容,使得开发者可以更加方便地使用动态大小的数据集合。

九、内存泄漏(了解)

9.1 内存泄漏概念

内存泄漏指因为疏忽或者错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费

9.2 内存泄漏的危害

长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

9.3 内存泄漏分类

C/C++程序中一般我们关心两种方面的内存泄漏

1.堆内存泄漏(Heap leak)

堆内存指的是程序执行种依据须要分配通过malloc/calloc/realloc/new等从堆中分配的一块内存,用完后必须通过调用相应的free或者delete删除。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

2.系统资源泄漏

指程序使用系统分配的资源,比方套接字,文件描述符,管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。


以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!
请添加图片描述

相关文章:

【C++】深入解析C/C++内存管理:new与delete的使用及原理

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类 本章将分享C为何放弃malloc/free系列&#xff0c;选择新系列new/delete去管理内存。深度探索new/delete的使用及其原理,m…...

递归--数据结构--黑马

递归 总结一句话&#xff0c;上手直接多刷Leetcode&#xff0c;比看这个更有用。 定义 递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集。 例如&#xff0c;单链表递归遍历的例子&#xff1a; void f(Node node) {if (node null) {retu…...

【3.1】贪心算法-解分发饼干

一、题目 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c; 每个孩子最多只能给一块饼干 。 对每个孩子i&#xff0c;都有一个 胃口值 g[i] &#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干j&#xff0c;都有一个…...

解决 Error running ‘Application‘: Command line is too long.

一、项目场景&#xff1a; 运行刚拉取下来的项目代码&#xff0c;出现下面问题描述的错误提示。 二、问题描述 Error running Application: Command line is too long. Shorten command line for Application or also for Spring Boot default configuration? 翻译翻译&…...

衡量与归因将是Netflix程序化广告业务的首要任务

作者&#xff1a;刀客doc 8月20日&#xff0c;Netflix宣布今年上半年&#xff0c;品牌的招商收入同比增长了150%&#xff0c;广告主来自旅游、汽车、零售商、快餐和大众快消等行业。这一消息提振了资本市场对Netflix广告业务的信心&#xff0c;8月20日收盘创下每股 698.54 美元…...

关于如何在已有qt项目中添加该项目的单元测试工程

关于如何在已有qt项目中添加该项目的单元测试工程 新建一个子目录工程&#xff0c;把已有项目作为子工程添加进去&#xff0c;然后新建单元测试工程也作为子工程添加进去。单元测试项目要独立于实际项目工程&#xff0c;确保去掉测试项目后&#xff0c;实际项目仍可以正常运行…...

深度剖析数字媒体产业链的无限潜力与创新生态

在当今信息爆炸的时代&#xff0c;数字媒体产业链正以势不可挡的姿态展现出其令人瞩目的无限潜力与创新生态。 数字媒体的发展潜力简直无可限量。从在线视频的爆发式增长&#xff0c;到虚拟现实和增强现实技术带来的沉浸式体验&#xff0c;再到社交媒体平台上丰富多彩的内容创…...

集团数字化转型方案(十二)

集团数字化转型方案致力于通过构建一个集成化的数字平台&#xff0c;全面应用大数据分析、人工智能、云计算和物联网等前沿技术&#xff0c;推动业务流程、管理模式和决策机制的全面升级。该方案将从业务流程的数字化改造开始&#xff0c;优化资源配置&#xff0c;提升运营效率…...

Andrid异步更新UI:Handler(二)深入了解:Message你真的会创建?它是如何子线程和主线程通知?

目录 为什么会有HandlerHandler的原理&#xff0c;以及对象讲解主线程的loop在哪里&#xff0c;为什么主线程loop没有阻塞呢&#xff1f;Looper如何保证唯一Handler为什么会引发内存泄漏呢&#xff1f;Message应该如何创建它&#xff1f; 一、为什么会有Handler 线程分为主线…...

2025计算机毕设50条小众好做的Java题目【计算机毕设选题推荐】

随着2025年的到来&#xff0c;计算机专业的学生们又迎来了毕业设计的关键时刻。对于大多数学生来说&#xff0c;选择一个合适的毕业设计题目往往是一项艰巨的任务。本文旨在为那些正在为毕业设计题目烦恼的同学们提供一些灵感和建议&#xff0c;特别是针对使用Java技术栈的同学…...

day06_算法训练

一. Stream流 1.1 Stream流概述 概念: jdk1.8以后提供的新的API, 主要用于批量操作数据(集合的另外一种操作方式),代码非常简洁 流式处理思想: 2.2 Stream对象获取 1.单列集合的Stream流对象获取 2.双列集合的Stream流对象获取 3.数组的Stream流对象获取 4.散装数据的St…...

@SpringBootTest单元测试中报错:无法自动装配,找不到 ‘XXX‘ 类型的 Bean

一开始照着网上教程讲Springboot原理中的代码来copy写的↓ import com.google.gson.Gson; import com.itheima.pojo.Result; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.cont…...

nodemon学习(一)简介、安装、配置、使用

nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。以前&#xff0c;我们开发一个node后端服务时&#xff0c;每次更改文件&#xff0c;均需重启一下&#xff0c;服务才能生效。这使我们的开发效率降低了很多。nodemon的出现&#xff0c;可以…...

【Qt从摄像头视频中获取数据】

有时候需要在视频上画图&#xff0c;所以需要能获取到每一帧视频数据。 以前从视频文件或视频流中得到帧&#xff0c;一般都是使用qt ffmpeg或qt vlc。 qt对显示处理视频大体有以下方法&#xff1a; QMediaPlayer QVideoWidget 这种方法只适合简单的显示视频功能&#xff…...

视频截取中的UI小组件

引言 视频截取在社交类 APP 中十分常见。有了上传视频的功能&#xff0c;就不可避免地需要提供截取和编辑的选项。如果我们过度依赖第三方库&#xff0c;项目的代码可能会变得异常臃肿&#xff0c;因为这些库往往包含许多我们用不到的功能&#xff0c;而且它们的 UI 样式和功能…...

java设计模式--结构型模式

结构性模式&#xff1a;适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式 适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09; 充当两个不兼容接口之间的桥梁&#xff0c;属于结构型设计模式。目的是将一个类的接口转换为另一个接口&am…...

消息中间件:Kafka消息丢失与堆积问题分析与解决方案

消息中间件&#xff1a;Kafka消息丢失与堆积问题分析与解决方案 Kafka作为分布式消息系统&#xff0c;广泛应用于实时数据流处理、大数据分析等领域。然而&#xff0c;在实际应用中&#xff0c;Kafka可能会面临消息丢失和消息堆积的问题&#xff0c;这些问题如果得不到有效处理…...

mac终端代理配置指南

终端代理配置指南 在 macOS 中&#xff0c;你可以通过几种不同的方法来配置终端代理。这里介绍两种常见的设置方式&#xff1a;使用 alias 和 shell 函数。 方法 1&#xff1a;使用 Alias 配置代理 打开终端配置文件 默认情况下&#xff0c;macOS 终端使用的是 zsh。如果你的系…...

mbedTLS生成客户端,服务端密钥及CA证书

1. mbedTLS源码&#xff1a;https://github.com/Mbed-TLS/mbedtls.git 2. 生成步骤&#xff1a; 2.1 编译上述源码 2.2 生成CA私钥和自签名证书&#xff1a; 进入编译的build目录&#xff0c;比如&#xff1a;/mbedtls-development/build# 2.2.1生成CA私钥 执行下面的命令&…...

如何有效应对突发技术故障:以网易云音乐为例

引言 在互联网行业&#xff0c;任何一个在线服务都可能遭遇突发的技术故障。这些故障不仅影响用户体验&#xff0c;还可能对公司的品牌形象造成损害。因此&#xff0c;如何快速响应并高效解决这些问题成为了每一个开发团队的重要课题。本文将以网易云音乐在2024年8月19日下午遭…...

上传文件到github仓库

REF: https://blog.csdn.net/litianxiang_kaola/article/details/74075151 已有repository&#xff0c;往仓库里更新内容 点击gitlab里的clone 在git bash中使用git clone&#xff0c;这个时候会将网上的仓库下载到本地&#xff0c;你可以把想要更新的内容直接拖到仓库里 …...

clip-path实现图片边角的裁剪

img {clip-path: polygon(0 7px,7px 0,calc(100% - 20px) 0,100% 20px,100% 100%,16px 100%,0 calc(100% - 16px));}每一个逗号隔开的就是路径坐标 左上角的两个点 0 7px &#xff0c;7px 0 右上角 calc(100% - 20px) 0,100% 20px 相当于通过这些点练成的线的圈起来的部分就是剩…...

【C++ Primer Plus习题】2.7

问题: 解答: #include <iostream> using namespace std;void print(int hour, int minute) {cout << "Time:" << hour << ":" << minute << endl; }int main() {int hour0;int minute 0;cout << "请输入…...

uboot中 fastboot udp 协议分析

注&#xff1a; 1. 本文所分析的fastboot源码不是android下的源码&#xff0c;而是恩智浦芯片厂商在IMX6UL芯片的uboot源码中自己实现的源码&#xff0c;二者不同&#xff0c;请读者注意区分。一些图片是网上找到的&#xff0c;出处不好注明&#xff0c;请见谅。 2. 分析fastbo…...

redis hash类型的命令

1.hset 格式&#xff1a; hset key field value [field value ...]&#xff08;value是字符串&#xff09; 返回值&#xff1a;设置成功的键值对的个数 2.hget&#xff1a;获取键值对 格式:hget key field 3.hexists&#xff1a;判断hash中是否存在指定 格式&#xff1a;…...

【OpenCV】 中使用 Lucas-Kanade 光流进行对象跟踪和路径映射

文章目录 一、说明二、什么是Lucas-Kanade 方法三、Lucas-Kanade 原理四、代码实现4.1 第 1 步&#xff1a;用户在第一帧绘制一个矩形4.2 第 2 步&#xff1a;从图像中提取关键点4.3 第 3 步&#xff1a;跟踪每一帧的关键点 一、说明 本文针对基于光流法的目标追踪进行叙述&am…...

ES 支持乐观锁吗?如何实现的?

本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理&#xff0c;列举常见的电商场景&#xff0c;关系型数据库的并发控制、ES的并发控制实践。 并发场景 不论是关系型数据库的应用&#xff0c;还是使用Elasticsearch做搜索加速的场景&#xff0c;只要有数据更新&…...

前端宝典十一:前端工程化稳定性方案

一、工程化体系介绍 1、什么是前端工程化 前端工程化 前端 软件工程&#xff1b;前端工程化 将工程方法系统化地应用到前端开发中&#xff1b;前端工程化 系统、严谨、可量化的方法开发、运营和维护前端应用程序&#xff1b;前端工程化 基于业务诉求&#xff0c;梳理出最…...

yum 数据源的切换

本来准备安装一个ntp 服务器时间进行同步&#xff0c;但是使用yum install ntp -y 但是却失败了 原因是yum自带的镜像源不能用了&#xff0c;所以要想使用yum 多功能只能切换yum 对应的镜像源了 如果你的服务商是可以使用wget命令的&#xff1a; wget -O /etc/yum.repos.d/Ce…...

MySQL入门学习-命令行工具.mysqlbinlog

MySQL 命令行工具mysqlbinlog用于处理二进制日志文件。 一、关于mysqlbinlog工具的详细介绍&#xff1a; 1、命令行工具mysqlbinlog的特点和使用方法&#xff1a; - 特点&#xff1a; - 可以解析和查看二进制日志文件的内容。 - 支持多种输出格式&#xff0c;如文本、SQ…...