内存管理
1 C++ 的内存分布2 C语言的内存管理3 C++的内存管理3.1 内置类型操作3.2 自定义类型操作 4 operator new与operator delete函数(重点)5 new和delete的实现原理5.1 内置类型5.2 自定义类型new的原理delete的原理new T[ N ] 的原理lete[]的原理 6 总结malloc/free和new/delete的区别 Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!!
1 C++ 的内存分布
内存管理是十分重要的内容,企业开发中多有服务器宕机的大事故,比如:
B站崩了两次:2023年3月5日晚20:20左右,许多网友表示在使用B站时,手机和电脑端都无法访问视频详情页,且手机端无法查看收藏夹与历史记录。
8月4日晚间,距离上次事故5个月后,又有许多网友反馈B站图片(视频封面)无法加载、视频无法打开、视频一直在缓冲。腾讯一级事故:
2023年3月29日凌晨,腾讯旗下的微信和QQ等业务曾出现崩溃状况,包括微信语音对话、朋友圈、微信支付,以及QQ文件传输、QQ空间和QQ邮箱在内的多个功能无法使用。
其中内存管理可能占有一定原因,只有我们打好内存管理的基础才能为大家做出贡献,那不然就只能赶快跑路了。
首先我们就要了解内存分布的情况是什么样的。
其中
栈又叫堆栈—非静态局部变量、函数参数、返回值等等。最重要的栈是向下增长的!空间有限但效率较高。内存映射段是高效的 I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,叫做进程间通信。堆用于程序运行时的动态内存分配,注意堆是向上增长的。会产生内存碎片(如果不停开辟空间会导致内存浪费)且效率较慢。数据段—储存全局数据和静态数据。代码段—可执行的代码 / 只读常量。堆和栈是我们常用到的区域,栈不需要我们进行管理,需要我们多加注意的就是堆区域
2 C语言的内存管理
我们回忆一下C语言的内存管理,大概是下面四个函数的使用:
malloc 直接开辟空间calloc 开辟并初始化空间realloc 扩容free 释放接下来我们来看C++ 的内存管理,来欣赏祖师爷的绝妙手笔~
3 C++的内存管理
首先C语言的内存管理可以在C++中使用,但是有些地方就显得比较复杂,因此我们需要C++的内存管理
C++的内存管理是通过new 操作符 和 delete 操作符来实现的。
3.1 内置类型操作
首先来看对于内置类型的操作:
int main(){//开辟申请一个int的空间int* p1 = new int;//开辟申请一个int的空间,并初始化为10int* p2 = new int(10);//开辟申请 3 个int的空间int* p3 = new int[3];//开辟申请 3 个int的空间,并初始化为1,2,3int* p4 = new int[3] {1, 2, 3};//释放空间delete p1;delete p2;delete[] p3;delete[] p4; return 0;}
通过一个new 就可以完成复杂的开辟空间操作。
注意:
每次使用完空间,一定要释放掉。申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[],注意:匹配起来使用。
3.2 自定义类型操作
对于自定义类型 new/delete 和 malloc/free最大区别是 new / delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
来看使用:
#include"Date.h"int main() {Date* p1 = new Date(2024, 2, 28);p1->show();delete p1;return 0;}
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会
4 operator new与operator delete函数(重点)
new 和 delete 是用户进行动态内存申请和释放的操作符,而 operator new与operator delete 是系统提供的全局函数,new 在底层就是通过调用operator new 来申请空间,delete就是通过operator delete 来释放空间。
到这里我们大概就知道了operator new与operator delete函数应该是对 malloc 和 free的封装。
我们进入反汇编就可以验证这一点:
// new() Fallback Ordering//// +----------+// |new_scalar<---------------+// +----^-----+ |// | |// +----+-------------+ +----+----+// |new_scalar_nothrow| |new_array|// +------------------+ +----^----+// |// +------------+----+// |new_array_nothrow|// +-----------------+_CRT_SECURITYCRITICAL_ATTRIBUTEvoid* __CRTDECL operator new(size_t const size){00007FF7C6A17D60 mov qword ptr [rsp+8],rcx 00007FF7C6A17D65 sub rsp,38h for (;;) { if (void* const block = malloc(size))00007FF7C6A17D69 mov rcx,qword ptr [size] 00007FF7C6A17D6E call malloc (07FF7C6A11401h) 00007FF7C6A17D73 mov qword ptr [rsp+20h],rax 00007FF7C6A17D78 cmp qword ptr [rsp+20h],0 00007FF7C6A17D7E je operator new+27h (07FF7C6A17D87h) { return block;00007FF7C6A17D80 mov rax,qword ptr [rsp+20h] 00007FF7C6A17D85 jmp operator new+4Bh (07FF7C6A17DABh) } if (_callnewh(size) == 0)00007FF7C6A17D87 mov rcx,qword ptr [size] 00007FF7C6A17D8C call _callnewh (07FF7C6A1150Ah) 00007FF7C6A17D91 test eax,eax 00007FF7C6A17D93 jne operator new+49h (07FF7C6A17DA9h) { if (size == SIZE_MAX)00007FF7C6A17D95 cmp qword ptr [size],0FFFFFFFFFFFFFFFFh 00007FF7C6A17D9B jne operator new+44h (07FF7C6A17DA4h) { __scrt_throw_std_bad_array_new_length();00007FF7C6A17D9D call __scrt_throw_std_bad_array_new_length (07FF7C6A1170Dh) }00007FF7C6A17DA2 jmp operator new+49h (07FF7C6A17DA9h) else { __scrt_throw_std_bad_alloc();00007FF7C6A17DA4 call __scrt_throw_std_bad_alloc (07FF7C6A111E0h) } } // The new handler was successful; try to allocate again... }00007FF7C6A17DA9 jmp operator new+9h (07FF7C6A17D69h) }00007FF7C6A17DAB add rsp,38h 00007FF7C6A17DAF ret
显然operator new与operator delete函数应该是对 malloc 和 free的封装。
5 new和delete的实现原理
5.1 内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL,需要我们来判断异常
5.2 自定义类型
new的原理
调用 operator new 函数申请空间在申请的空间上执行构造函数,完成对象的构造。delete的原理
在空间上执行析构函数,完成资源清理工作。调用operator delete函数释放空间。new T[ N ] 的原理
调用operator new [ ]函数,在operator new[ ]实际调用operator new 函数完成N个对象空间的申请。在申请的空间执行N次构造函数。注意 开辟空间会多开一些来储存个数N。lete[]的原理
在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间6 总结
malloc/free和new/delete的区别
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。
不同的地方是: