《C++》动态内存管理

一、本章重点

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、事后查错型。如泄漏检测工具。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李逢溪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值