一、本章重点
1、介绍c/c++内存分布
2、回顾malloc、calloc、realloc、free
3、介绍new、delete操作符
4、分析new/malloc和delete/free的区别
5、介绍定位new
6、浅谈内存泄露
二、c/c++内存分布情况
了解c语言的都知道内存一般被划分为栈区、堆区、数据段、代码段
以下图片是一个内存分区意向图(地址从高到低,栈区的地址最高),由于不想涉及系统,其实在栈区之上还有个内核空间(用户不可进行读写),在栈区和堆区之间还有一个内存映射区(该区域的作用会在系统章节详细介绍)。
?栈区:一般存储局部变量、函数参数。使用习惯是先使用高地址的空间,再使用低地址空间,释放空间时,先释放低地址,再释放高地址。一般栈区的大小在8m左右。
堆区:由程序员自由操作的内存空间,可以从堆区进行申请和释放空间,c语言申请堆区用malloc、calloc、realloc,释放使用free。如果使用完堆区内存之后,不释放空间会导致内存泄露,造成电脑卡顿。当然在程序终止之后,系统会自动回收。但如果程序24小时一直在跑,用完不释放将造成比较大的后果。还需要注意的是,申请的空间释放时必须全部释放,不能只释放一部分,也不能重复释放堆区内存。一般堆区大小在1G左右。
数据段:一般存储全局变量、静态变量,因此也有人称之为全局区/静态区。
代码段:一般存储只读常量、可执行代码。
三、回顾malloc、calloc、realloc、free
?
malloc用来在堆区申请空间,calloc也是在堆区申请空间,它们唯一的区别是calloc在申请空间之后同时会初始化为0。需要知道的是malloc和calloc申请空间失败时返回null
realloc用来调整申请的空间,一般用来实现动态的顺序表。
调整分为两种情况:
1、在原空间调整
2、释放原空间,重新开辟一块新的空间。
free用来释放申请的堆区内存。如果释放的内存指向空,则什么也不会发生。
四、介绍new、delete操作符
一、malloc和new
?new是一个操作符,用法:
1、new+类型,返回的是对应类型的指针。
2、new+类型[size],返回的是这块空间的首元素的地址。
咋一看,new和malloc好像没什么区别,都不会对内置类型进行初始化,但遇到自定义的类型,new可比malloc好多了。
?可以看出,new申请空间的同时会调用构造函数进行初始化,而malloc只是开空间。
还有就是new申请空间失败时会抛异常,而malloc则返回的是null。具体什么是异常,后面会出对应的章节进行介绍。对比new和malloc之后,我们也可以猜想出,new底层或许调用了malloc。确实是这样的,new操作符调用了operator?new函数,它是一个全局函数。而operator?new函数调用了malloc,同时用抛异常的方式处理申请空间失败。换言之,new操作符是operator new函数和构造函数的组合。
二、free和delete
delete的使用方法:
如果p是单个元素的地址(new +?类型)
使用delete p释放空间
如果p是多个元素的首地址(new+?类型 [ ])
使用delete [ ] p释放空间
?
free是用来释放堆区内存的,delete也是如此。只不过delete在释放空间之前会调用析构函数。delete和new一样,底层会调用operator?delete函数,该函数调用的是free。换言之,delete是free+析构函数的组合。
需要注意的是delete?和?new配对,delete[]和new[]配对,如果用delete去释放new[]的空间可能会导致不良的后果,注意这里是可能,一般内置类型不会有影响,建议一定要配对使用。
五、定位new
什么是定位new?简单来说就是显示的调用构造函数初始化申请的空间,一般配合内存池使用。那什么是内存池呢?简单来说就是提前向系统申请的一大块未初始化的空间,因为频繁向系统申请空间会影响效率,然后我们需要空间的时候就去内存池去切一小块空间来使用。
但切的空间是未初始化的,这时候我们就需要用定位new来初始化内存池要来的空间。
首先,如何显示调用构造函数?下面这种写法可行吗?
?化红线了,显然不行,构造函数并不能向其他成员函数那样显示的调用,而要使用定位new。
使用格式:
new(ptr)type或者new(ptr)type(initializer-list)
其中ptr是一个指针,type为类型,initializer-list为初始化列表。
?我们也可以传参调用,如下。
我们在来强化一下:
new =?operator?new +?构造函数
delete =?析构函数+ operator delete
?
六、浅谈内存泄露
什么是内存泄露?是内存丢了?还是指针丢了?
答:指针丢了。
内存泄露本质就是一块空间你使用完之后,没有释放该空间而导致内存“泄露了”。
但如何避免内存泄露呢?
1、使用检测内存泄露工具(很多工具不靠谱或者收费昂贵)
2、养成良好的代码素养,规范编码习惯。
3、采用RAII思想或者智能指针来管理资源。
总结:内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。
|