C/C++ 内存管理

1. C/C++内存分布

我们先来看下面的一段代码和相关问题
在这里插入图片描述

  1. char2 只是一个字符数组,因此存放在栈上。
  2. 星char2 在 栈上,因为数组名sizeof的时候代表整个数组,但是进行运算的时候,比如说解引用 它是代表首元素的地址。
    图示:
    在这里插入图片描述
    3.PChar3在栈上,首先const限制*PChar3,不能通过PChar3来修改PChar3指向的空间内容,但是指针变量PChar3可以改变,因此PChar3不可能在常量区。
  3. *PChar3 在常量区,原因如下:
    在这里插入图片描述
    4.指针变量ptr1在栈上,指向的内容在堆上,因此 * ptr 在堆上。
    在这里插入图片描述
    【说明】
  4. 又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  5. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
  6. 用于程序运行时动态内存分配,堆是可以上增长的。
  7. 数据段–存储全局数据和静态数据。
  8. 代码段–可执行的代码/只读常量。

2. C语言中动态内存管理方式:malloc/calloc/realloc/free

在这里插入图片描述
【面试题】

  1. malloc/calloc/realloc的区别?
    malloc 函数用于分配指定大小的内存块,它从堆(heap)中分配内存,但不初始化这些内存。calloc 会将分配的内存初始化为零。realloc 函数用于扩容。
  2. malloc的实现原理? glibc中malloc实现原理

3. C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

3.1 new/delete操作内置类型

在这里插入图片描述
在这里插入图片描述
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。
例子:
在这里插入图片描述
new默认不初始化,但是它也可以初始化,如下:
在这里插入图片描述
注意 :对于内置类型开空间使用malloc或者new几乎是一样的

int* p3 = (int*)malloc(sizeof(int)); // C
int* p4 = new int;

3.2 new和delete操作自定义类型

在这里插入图片描述
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

4. operator new与operator delete函数(重要点进行讲解)

4.1 operator new与operator delete函数(重点)

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
在这里插入图片描述
上面会有同学有疑问为什么要operator new,operator delete呢?直接调malloc不香吗?为啥要搞这个东西?有个原因在。首先malloc 失败的结果是什么?是返回空。所有以前用malloc的时候都会检查是否为空。new 呢? C++引出了一个叫异常的东西。通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
下面给你们看个new好用的代码:

在这里插入图片描述
为什么不是malloc+构造函数,而是operator new+函数构造,如果operator new 开空间失败了,malloc是返回0。operator new是封装(实际就是封装malloc),所以new失败抛异常实际上是在operator new开空间时(malloc+失败抛异常),从表层角度看malloc是一个函数的用法,new是一个操作符的用法。从底层角度看,new就是malloc,但是它在malloc的基础上加了很多东西,new其实比malloc多做了很多事情,多做了构造函数,失败了要抛异常。
还有个问题就是 new ,delete ,malloc ,free能不能混着使用,我这里建议大家配对使用。因为有时候能对,有时候可能程序会崩溃。混合使用可能导致释放位置不对。
在这里插入图片描述

5. new和delete的实现原理

5.1 内置类型

在这里插入图片描述

5.2 自定义类型

在这里插入图片描述
代码:
在这里插入图片描述

new底层原理图示:
在这里插入图片描述
delete底层原理图示:
在这里插入图片描述
析构 和 operator delete 释放的是不是同一个东西? 答案是:不是,operator delete delete的是谁?是p2指向的这块空间析构,析构是这个A对象上的资源的清理(当然是A对象有资源才需要清理,没有资源要清理,调用析构函数,就直接执行函数体的代码,比如说就只打印了一句)。
在这里插入图片描述

6. 定位new表达式(placement-new) (了解)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:

new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表

使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

在这里插入图片描述

7. 常见面试题

7.1 malloc/free和new/delete的区别

在这里插入图片描述

7.2 内存泄漏

7.2.1 什么是内存泄漏,内存泄漏的危害

在这里插入图片描述
在这里插入图片描述

7.2.2 内存泄漏分类(了解)

在这里插入图片描述

7.2.3 如何检测内存泄漏(了解)

在vs下,可以使用windows操作系统提供的_CrtDumpMemoryLeaks() 函数进行简单检测,该函数只报出了大概泄漏了多少个字节,没有其他更准确的位置信息。
在这里插入图片描述
因此写代码时一定要小心,尤其是动态内存操作时,一定要记着释放。但有些情况下总是防不胜防,简单的可以采用上述方式快速定位下。如果工程比较大,内存泄漏位置比较多,不太好查时一般都是借助第三方内存泄漏检测工具处理的。

7.2.4如何避免内存泄漏

  1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
  2. 采用RAII思想或者智能指针来管理资源。
  3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
  4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
    总结一下:
    内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少年没有乌托邦。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值