【C++】内存管理(new/delete) 目录1、内存的区域划分2、C的内存管理方式new和delete操作符new 和 delete 的原理malloc/free和new/delete的区别内存泄漏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; 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); }1. 选择题选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)globalVar在哪里____ staticGlobalVar在哪里____staticVar在哪里____ localVar在哪里____num1 在哪里____char2在哪里____ *char2在哪里___pChar3在哪里____ *pChar3在哪里____ptr1在哪里____ *ptr1在哪里____2. 填空题sizeof(num1) ____;sizeof(char2) ____; strlen(char2) ____;sizeof(pChar3) ____; strlen(pChar3) ____;sizeof(ptr1) ____;存储区域说明栈Stack存放局部变量、函数参数等由编译器自动分配和释放。堆Heap动态分配的内存malloc/calloc/realloc需手动free。数据段静态区存放全局变量、静态变量static程序结束时释放。代码段常量区存放常量如字符串常量abcd和程序代码。栈Stack分配方式由编译器自动管理函数调用时压栈返回时弹栈。大小限制较小Linux 默认 8MB可通过ulimit -s调整。生长方向向下地址递减如0xFFFF → 0x0000。碎片问题无碎片LIFO 结构保证连续分配。访问速度最快CPU 直接支持栈指针操作。典型用途局部变量、函数参数、返回地址。堆Heap分配方式手动管理malloc/new分配free/delete释放。大小限制受系统虚拟内存限制32 位系统最多 4GB64 位系统理论无限。生长方向无固定方向由内存分配器决定。碎片问题频繁分配/释放会导致内存碎片。访问速度较慢需通过指针间接寻址。典型用途动态分配的对象、大型数据结构。数据段Data Segment分配方式.data显式初始化的全局/静态变量。.bss未初始化的全局/静态变量运行时清零。大小限制受可执行文件格式和系统限制。生长方向无明确方向由链接器布局决定。碎片问题无编译时已固定布局。访问速度快与代码段同级但可读写。典型用途全局变量、静态变量、常量可能优化到代码段。代码段Code Segment / Text Segment分配方式编译器将程序代码和常量写入可执行文件。大小限制受可执行文件大小限制。生长方向无明确方向由链接器布局决定。碎片问题无只读加载时固定。访问速度快CPU 直接读取通常缓存到指令缓存。典型用途程序指令、字符串常量、constexpr常量。关键补充栈溢出递归过深或局部变量过大会导致栈溢出Stack Overflow。堆碎片可通过内存池或智能指针如std::make_shared缓解。常量折叠编译器可能将const变量优化到代码段如const int x 42;。线程栈每个线程有独立的栈共享堆和数据段/代码段。2、C的内存管理方式C语言内存管理方式在C中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。new和delete操作符使用的基本形式类型名 变量名 new 类型名delete 变量名示例int* p new intdelete p申请的同时可以初始化类型名 变量名 new 类型名 n delete 变量名圆括号内 n 就是初始化的内容。如果要一次性申请多个空间数组类型名 变量名 new 类型名[n] delete[ ] 变量名方括号内 n 是申请的空间大小。申请的同时可以对数组初始化类型名 变量名 new 类型名[n] { r1,r2,r3,...} 如果初始化时采用部分初始化其余的数组元素会被初始化为 0。new 和 malloc 的最大区别用 new 来动态开辟一个自定义类型的空间没有用花括号初始化会去调用该自定义类型的默认构造函数如果没有默认构造函数会报错。用 delete 释放该空间时会去调用析构函数。如果某个类的构造函数是多参数的使用 new 时该如何初始化开辟单个空间类型名 变量名 new 类型名 类型名r1,r2 )delete 变量名开辟多个空间类型名 变量名 new 类型名[ n ] 类型名r1,r2 ,类型名r1,r2 ...)delete[ ] 变量名new 和 delete 的原理new 和 delete 在处理内置类型时和 malloc 和 free 差不多但在处理自定义类型有很大区别new 通过调用 operator new 函数 operator new 函数再调用 malloc 函数来开空间再在开辟的空间调用构造函数。delete先调用析构函数再调用operator delete 函数operator delete 函数再调用 free 函数来释放空间。delete先调用析构函数再调用operator delete 函数的顺序不能改变在堆上申请了一个堆数据结构堆的构造函数已完成构造如果 delete 函数先调用 operator delete 函数 operator delete 函数调用的 free 函数会释放该堆的空间_array 指向的空间内存泄漏。delete [ ] 变量名如果每个元素是类类型会依次调用每个对象的析构函数然后 free 这块空间。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在释放空间前会调用析构函数完成空间中资源的清理内存泄漏内存泄漏的危害对于短时间运行的程序程序进程结束的时候申请的内存会被自动释放长期运行的程序出现内存泄漏影响很大如操作系统、后台服务等等出现内存泄漏会导致响应越来越慢最终卡死。短时间内出现大量内存泄漏容易发现而每次内存泄漏的很少则很难发现。