文章目录什么是内存管理C内存区域的划分C语言中动态内存管理方式malloc、calloc、realloc和freeC内存管理方式new/delete管理体系C内存开辟失败与抛异常new和delete的底层原理什么是内存管理内存管理就是程序在运行时合理申请、使用、释放内存的整套规则和方法.如果不进行内存管理那么程序在运行时就会越跑越慢甚至直接卡死.C内存区域的划分程序在运行时内存被划分为五块。栈非静态局部变量、函数参数、返回值。特点是会自动创建和自动销毁堆malloc或者new动态申请的空间需要手动申请也需要手动释放数据段也被称为静态区用来存放全局变量和非const静态变量代码段也叫常量区用来存放可执行代码、字符串常量和只读数据。这里解释一下什么是可执行代码就是你写的函数语句编译器编译后会生成一条条的机器指令cpu会逐条执行。字符串常量就是用双引号“···”括起来的字符串比如“hello world”。它们都是只读的。只读数据除了字符串常量外其他被标记为只读的全局/静态数据比如const修饰的全局变量、枚举常量等等。补充栈、静态区和堆的内存释放时机栈函数执行结束代码块结束时自动释放。什么时候申请进入函数或者创建局部变量的时候。静态区整个程序运行期间永不释放直到程序退出才由系统回收堆必须用free/delete手动释放如果不释放的话会导致内存泄露的风险下面用一道题目来巩固知识点intglobalVar1;staticintstaticGlobalVar1;voidTest(){staticintstaticVar1;intlocalVar1;intnum1[10]{1,2,3,4};选项:A.栈 B.堆 C.数据段(静态区)D.代码段(常量区)globalVar在哪里____ staticGlobalVar在哪里____ staticVar在哪里____ localVar在哪里____ num1 在哪里____charchar2[]abcd;constchar*pChar3abcd;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);}选项:A.栈 B.堆 C.数据段(静态区)D.代码段(常量区)char2在哪里____*char2在哪里___ pChar3在哪里____*pChar3在哪里____ ptr1在哪里____*ptr1在哪里____解析1globalVar是全局变量存放在静态区选CstaticGlobalVar是静态全局变量存放在静态区选CstaticVar是静态局部变量存放在静态区中选ClocalVar是局部变量存放在栈中选Anum1是指针存放在栈上选A解析2char2指针栈上选A*char2是指首元素a也在栈上选ApChar3是指针栈上选A*pChar3 指向字符串常量 “abcd” 的第一个字符 ‘a’字符串常量存储在代码段常量区是只读数据。ptr1 是函数内定义的局部指针变量指针本身存储在栈上。*ptr1 是 malloc 动态分配的堆内存空间因此该数据存储在堆上。补充「向上增长」和「向下增长」内存地址是从 低地址小数字到高地址大数字 排列的我们可以把内存想象成一条从左到右的数轴栈向下增长地址从高到低新分配的栈帧 / 局部变量会被放在比之前变量地址更小的位置。比如先定义 int a 在地址 0xffff再定义 int bb 就会在 0xfffb地址变小。堆向上增长地址从低到高新 malloc/new 出来的内存会被放在比之前分配地址更大的位置。比如先申请一块内存在 0x1000再申请一块新内存会在 0x1010地址变大。C语言中动态内存管理方式malloc、calloc、realloc和freemalloc、calloc、realloc和free区别和特点mallocvoid*malloc(size_tsize);作用向堆申请一块连续的内存空间。特点只分配不初始化 速度快无需清零参数是总字节数callocvoid*calloc(size_tnum,size_tsize);作用分配 num 个、每个大小为 size 的连续内存。特点分配后自动全部初始化为 0参数是元素个数 单个元素大小reallocvoid*realloc(void*ptr,size_tnew_size);作用修改已经分配好的内存大小扩容 / 缩容。特点原有内存数据会保留可能返回新地址内存不够时 若 ptrNULL → 等价于 mallocfreevoidfree(void*ptr);作用把动态分配的内存还给操作系统。特点只能释放 malloc/calloc/realloc 分配的内存释放后指针变成野指针建议手动置 NULL不调用会造成内存泄漏注意可能会考的面试题malloc、calloc、realloc的区别手动实现mallocC内存管理方式new/delete管理体系用法new对标C语言中的mallocdelete类似于free下面是他们的用法内置类型//单个空间开辟和释放voidTest(){int*ptrnewint;delete ptr;}//给它初始化int*ptrnewint(1);//多个空间的开辟和释放:用[]voidTest(){int*ptrnewint[10];delete[]ptr;、//多个空间的初始化用{}int*ptrnewint[5]{1,2,3,4,5};int*ptrnewint[10]{1,2,3,4,5};int*ptrnewint[10]{0};}自定义类型对于自定义类型C在申请空间的时候会自动调用构造函数释放空间的时候会自动调用析构函数。可以发现对比C语言节省了初始化和销毁的步骤使用起来更加简单方便了。对象开辟空间的方法A*p1new A;//有默认构造函数并开辟一个对象大小空间A*p3new A[3];//有默认构造函数并开辟多个对象大小空间A*p2newA(2,2);//没有默认构造函数开辟//拷贝构造多个对象大小空间最基础版Aaa1(1,1);Aaa2(2,2);Aaa3(3,3);A*p3new A[3]{aa1,aa2,aa3};//拷贝构造多个对象大小空间最基础版A*p4new A[3]{A(1,1),A(2,2),A(3,3)};//拷贝构造多个对象大小空间使用C11特性版多参数构造隐式类型转换A*p5new A[3]{{1,1},{2,2},{3,3}};C内存开辟失败与抛异常C内存开辟失败与C语言的也有所不同C语言malloc失败后返回空而new失败后不是返回空而是抛异常。弹窗提示开辟内存失败。开辟内存太多而无法实现现在出现了这种异常在C中我们要尝试并捕获这种异常try 是异常捕获的入口区域用来包裹可能抛出异常的代码。当 try 内部代码执行时如果发生异常程序会立即跳转到对应的 catch 块处理而不是直接崩溃。catch 是异常处理的分支用来捕获并处理 try 块中抛出的特定类型异常。当 try 中抛出匹配类型的异常时catch 块会被执行避免程序直接终止。std::exception 是 C 标准库中所有标准异常的基类定义在 头文件中。它是一个抽象基类派生出 std::bad_alloc内存分配失败、std::out_of_range越界访问等具体异常类型。new和delete的底层原理new、delete和operator new、operator delete的关系new 和 delete 是用户进行动态内存申请和释放的操作符operator new 和 operator delete 是系统提供的全局函数new在底层调用 operator new全局函数来申请空间delete 在底层通过 operator delete 全局函数来释放空间。operator newvoid*__CRTDECL operatornew(size_tsize)_THROW1(_STD bad_alloc){// try to allocate size bytesvoid*p;while((pmalloc(size))0)if(_callnewh(size)0){// report no memory// 如果申请内存失败了这里会抛出bad_alloc 类型异常staticconststd::bad_alloc nomem;_RAISE(nomem);}return(p);}该函数实际通过malloc来申请空间当malloc申请空间成功时直接返回申请空间失败尝试执行空间不足应对措施。如果改应对措施用户设置了则继续申请否则抛异常。operator deletevoidoperatordelete(void*pUserData){_CrtMemBlockHeader*pHead;RTCCALLBACK(_RTC_Free_hook,(pUserData,0));if(pUserDataNULL)return;_mlock(_HEAP_LOCK);/* block other threads */__TRY/* get a pointer to memory block header */pHeadpHdr(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_dbg( pUserData, pHead-nBlockUse );可见operator delete最终也是通过free来释放空间的。new的原理调用operator new函数申请空间在申请的空间上执行构造函数完成对象的初始化delete的原理在空间上执行析构函数完成对象中资源的清理工作调用operator delete函数释放对象的空间new T[N]的原理调用operator new[]函数在operator new[]中实际调用operator new函数完成N个对象空间的申请在申请的空间上执行N次构造函数delete[]的原理3. 在释放的对象空间上执行N次析构函数完成N个对象中资源的清理4. 调用operator delete[]释放空间实际在operator delete[]中调用operator delete来释放空间完。