C++内存管理:从内存分布到new/delete底层原理 一、C/C内存分布在开始讨论动态内存管理之前我们先来搞清楚一个问题程序中的各种变量分别存储在内存的哪个区域先看下面这段代码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); }你能准确说出每个变量存储在哪个区域吗globalvar→ 数据段静态区staticGlobalvar→ 数据段静态区staticvar→ 数据段静态区localvar→ 栈num1→ 栈char2→ 栈*char2→ 栈因为char2是数组内容在栈上pChar3→ 栈*pChar3→ 代码段常量区因为指向的是字符串常量ptr1→ 栈*ptr1→ 堆内存区域划分区域存储内容特点栈非静态局部变量、函数参数、返回值等向下增长自动管理堆动态分配的内存向上增长需手动管理数据段静态区全局变量、静态变量程序运行时分配结束时释放代码段常量区可执行代码、只读常量只读不可修改二、C语言的动态内存管理在C语言中我们使用malloc、calloc、realloc和free来管理动态内存。malloc/calloc/realloc 的区别函数参数初始化返回值malloc字节数不初始化void*calloc个数每个大小初始化为0void*realloc原指针新大小不初始化void*// 使用示例 int* p2 (int*)malloc(4 * sizeof(int)); // 申请4个int int* p3 (int*)calloc(4, sizeof(int)); // 申请4个int并初始化为0 int* p4 (int*)realloc(p2, sizeof(int)*10); // 扩容到10个int // 注意如果realloc扩容成功p2会被自动释放不需要再free(p2) free(p3); free(p4);三、C的内存管理方式C除了兼容C的内存管理方式外还引入了new和delete操作符。3.1 内置类型的使用// 申请和释放单个对象 int* ptr1 new int; // 申请一个int int* ptr2 new int(10); // 申请一个int并初始化为10 delete ptr1; delete ptr2; // 申请和释放数组 int* ptr3 new int[10]; // 申请10个int delete[] ptr3; // 注意必须使用delete[]3.2 自定义类型的使用new和delete与malloc和free最大的区别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() { // malloc只会开辟空间不会调用构造函数 A* p1 (A*)malloc(sizeof(A)); // new会开辟空间 调用构造函数 A* p2 new A(10); // free只会释放空间不会调用析构函数 free(p1); // delete会调用析构函数 释放空间 delete p2; return 0; }四、operator new 与 operator delete很多人不知道的是new和delete实际上是操作符而operator new和operator delete是全局函数。底层实现原理// operator new 的简化实现 void* __CRTDECL operator new(size_t size) { void* p; while ((p malloc(size)) 0) { if (_callnewh(size) 0) { // 申请失败抛出 bad_alloc 异常 throw std::bad_alloc(); } } return p; } // operator delete 的简化实现 void operator delete(void* pUserData) { if (pUserData NULL) return; free(pUserData); }关键点operator new底层调用malloc申请失败时抛异常而不是返回NULLoperator delete底层调用free五、new 和 delete 的实现原理5.1 内置类型对于内置类型new和malloc、delete和free基本类似区别在于new失败时抛异常malloc失败返回NULLnew[]/delete[]用于连续空间5.2 自定义类型new的原理调用operator new申请空间在申请的空间上执行构造函数delete的原理在空间上执行析构函数调用operator delete释放空间new T[N]的原理调用operator new[]实际调用operator new申请N个对象空间执行N次构造函数delete[]的原理执行N次析构函数调用operator delete[]实际调用operator delete释放空间六、定位new表达式placement new定位new允许在已分配的内存上调用构造函数初始化对象。// 使用场景内存池分配的内存需要初始化 A* p1 (A*)malloc(sizeof(A)); // 只分配内存未构造对象 new(p1) A(10); // 在p1指向的内存上构造对象 p1-~A(); // 显式调用析构函数 free(p1);适用场景配合内存池使用在已分配的内存上创建对象。七、malloc/free 与 new/delete 的区别对比项malloc/freenew/delete本质函数操作符初始化不会初始化可以初始化大小计算需手动计算编译器自动计算返回值void*需强转类型安全无需强转失败处理返回NULL需判空抛异常需捕获自定义类型不调用构造/析构调用构造/析构八、常见问题与最佳实践8.1 内存泄漏内存泄漏是指动态分配的内存没有被正确释放导致内存浪费。常见场景忘记delete/free异常导致delete未执行使用new[]却用delete释放8.2 最佳实践匹配使用new配deletenew[]配delete[]RAII原则使用智能指针unique_ptr、shared_ptr管理资源避免裸指针尽可能使用智能指针定期检查使用内存检测工具定期检查内存泄漏总结C的内存管理非常灵活但也很容易出错。记住以下几点理解内存分布栈、堆、数据段、代码段掌握new/delete与malloc/free的区别理解operator new/operator delete的底层原理遵循最佳实践使用智能指针管理内存