资讯动态

C++初阶(05):内存管理

发布时间:2026/8/29 20:06:55 来源:尧图企业网站定制
如果你在阅读过程中有任何疑问或想要进一步探讨的内容欢迎在评论区畅所欲言我们一起学习、共同成长~ 如果你觉得这篇文章还不错不妨顺手点个赞、加入收藏并分享给更多的朋友噢~1. C/C 程序内存区域划分内存区域描述内核空间用户代码不能读写栈主要存储非静态局部变量、函数参数、函数返回值等其空间由编译器自动分配和释放一般较小。不存在手动释放导致的内存泄漏等问题向下增长高地址→低地址内存映射段通过高效I/O映射方式将共享动态内存库映射到进程地址空间实现内存高效访问堆程序运行时用于动态内存分配的区域手动申请和释放空间向上增长低地址→高地址数据段存储全局数据、静态数据代码段存储只读常量和可执行代码2. C语言动态内存管理mallocfree#include stdio.h #include stdlib.h int main() { int* p(int*)malloc(sizeof(int)); // 动态申请单个int *p1; free(p); pNULL; // 置空防止野指针 int n5; int* arr(int*)malloc(n*sizeof(int)); // 动态申请连续n个int arr[0]1;arr[1]2; free(arr); arrNULL; return 0; }C语言动态内存管理3. C动态内存管理new/delete 操作符申请空间new释放空间delete单个元素空间type* pnew type;​type* pnew type(初值);delete p;连续空间type* pnew type[size];​type* pnew type[size]{初值};delete[] p;3.1 new/delete 操作内置类型3.1.1 单个元素空间int* p1new int; *p110; delete p1; int* p2new int(20); delete p2;3.1.2 连续空间int* p3new int[3]; p[0]1; p[1]2; p[2]3; delete[] p3; int* p4new int[3]{1,2,3}; delete[] p4;3.2 new/delete 操作自定义类型class Myclass { public: Myclass():val(0),name(默认名){} ~Myclass(){} void Print(){} private: int data; string name; }; int main() { Myclass* anew Myclass; a-Print; delete a; anullptr; // 置空防止野指针 Myclass* bnew Myclass[2]; delete[] b; bnullptr; return 0; }4. new 和 delete 的实现原理4.1 自定义类型new Tdelete p步骤①调用operator new函数 → 内部调用malloc申请堆内存步骤①调用p所指对象的析构函数释放类内部资源步骤②在申请到的内存上调用构造函数初始化对象成员步骤②调用operator delete函数 → 内部调用free归还堆内存步骤③返回指向该对象的指针T*—new T[N]delete[] p步骤①调用operator new[]申请整个数组内存其实现中通常转发给operator new函数 → 内部调用malloc申请整个堆内存步骤①获取数组长度按构造的逆序依次调用N次析构函数步骤②在申请到的连续内存上依次调用N次构造函数步骤②调用operator delete[]函数其实现中通常转发给operator delete函数 → 内部调用free归还整个堆内存步骤③返回指向数组首元素的指针T*—代码层面int n5; int* a(int*)malloc(n*sizeof(int)); free(a); int* b(int*)operator new(n*sizeof(int)); operator delete(b);4.2 内置类型内置类型无构造函数、无析构函数new/delete操作自定义类型的底层行为去掉调用构造/析构函数即new/delete操作内置类型的底层行为。new T[N]/delete[]同理。可以说内置类型中new ≈ mallocdelete ≈ free区别之一——申请空间失败时new抛异常malloc返回NULL。4.3 优先用new/deletemalloc仅申请内存不调用构造函数初始化对象成员free仅归还内存不调用析构函数释放类内部资源可能导致资源泄露。所以C中申请/释放动态内存一般优先使用new/delete尤其是操作自定义类型时。4.4 申请与释放不匹配new/delete 形式不匹配不属于类型不兼容编译器只为类型不兼容报错但不建议下表的写法。内置类型int* p new int[10];delete p;内置类型无析构但底层free直接释放整个内存块正常运行无泄露不崩溃int* p new int;delete[] p;delete[] p; 认为 p 指向数组试图读取数组长度而该信息new []时才存在属于未定义常崩溃自定义类型MyClass* p new MyClass[10];delete p;delete p 认为 p 指向单个对象只析构第 1 个其余泄漏崩溃MyClass* p new MyClass;delete[] p;delete[]读取不存在的数组长度析构越界崩溃5. 定位 new 表达式了解即可定位 new 表达式用于在已分配的原始内存空间中调用构造函数初始化一个对象。5.1 使用格式new (一个指向已分配的原始内存空间的指针) 要创建的对象的数据类型new (一个指向已分配的原始内存空间的指针) 要创建的对象的数据类型(类型的初始化列表)5.2 使用场景定位 new 表达式常配合未初始化内存如内存池分配的内存使用。内存池分配的内存未初始化用于自定义类型对象时需借助定位 new 表达式显式调用构造函数以完成对象初始化#include iostream class A { public: A(int a 0) : _a(a) { std::cout A(): this std::endl; } ~A() { std::cout ~A(): this std::endl; } private: int _a; }; int main() { // 使用malloc分配A对象大小的内存空间 A* p1 (A*)malloc(sizeof(A)); // 使用定位new表达式初始化对象 new(p1)A; p1-~A(); free(p1); // 使用operator new分配A对象大小的内存空间 A* p2 (A*)operator new(sizeof(A)); // 使用定位new表达式初始化对象并传参 new(p2)A(10); p2-~A(); operator delete(p2); return 0; }5.常见面试题5.1malloc/free 和 new/delete 的区别malloc/freenew/delete同都从堆上申请空间都需用户手动释放异①类型函数操作符②申请的空间的初始化情况malloc不调用构造函数所以不初始化new调用构造函数所以初始化③空间大小指定malloc申请空间时手动计算空间大小并传递new后指定类型即可④强制转类型malloc申请成功返回void*C中无法直接赋值所以使用时需显式转类型new后为类型返回type*无需强转⑤申请空间失败malloc返回NULL所以使用时必须判空new抛异常需捕获异常⑥申请自定义类型对象空间不调用构造/析构函数new申请空间后调用构造函数delete释放空间前调用析构函数5.2内存泄露5.2.1内存泄漏是什么及其危害内存泄漏程序未能释放不再使用的内存。不是指内存物理消失而是失去对内存的控制导致浪费。危害长期运行的程序出现内存泄漏会导致响应变慢最终卡死。void Test() { // 内存申请了忘记释放 int* p1 (int*)malloc(sizeof(int)); int* p2 new int; int* p3 new int[10]; Func(); // 假设这里Func函数抛异常那导致 delete[] p3未执行p3未释放 delete[] p3; }5.2.2内存泄漏分类C/C中我们一般关心两方面的内存泄漏堆内存泄露从堆分配到的内存没有调用正确对应的free或delete释放。系统资源泄露使用系统分配的资源如套接字、文件描述等没有使用对应函数释放导致资源浪费。严重可导致系统效能下降、执行不稳定。5.2.3如何避免内存泄露事前预防1规范编码申请的内存记得匹配对应释放函数2采用RAII思想或智能指针管理资源事后差错泄露检测工具

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价