C++中的内存分配

C++中的内存分配

C++内存分配的三种方式

1. 从静态存储区分配:

此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储。

2. 在栈区分配:

相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率高,但容量有限。

3. 在堆区分配:

动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指定,灵活。但有内存泄露等问题。

动态分配内存

C++中通过new运算符进行动态内存申请

C++中的动态内存分配是基于类型进行的

malloc函数也可以用于指定大小的内存分配


new分配内存对应着delete释放内存

malloc分配内存对应着free释放内存


malloc和new的区别

1.申请内存的位置

new操作符是从自由分配区上为对象分配内存空间的,而malloc是在堆上分配内存的

自由分配区:是由操作符new决定的,可能是静态存储区,也可能是堆,定位new甚至可以不为对象分配内存

2.返回的类型

new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。

而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图方法自己没被授权的内存区域。关于C++的类型安全性可说的又有很多了。

3.内存分配失败时的返回值

new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。

4.是否需要指定大小

使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。

5.是否调用构造/析构函数

使用new操作符来分配对象内存时会经历三个步骤:

  • 第一步:调用operator new 函数(对于数组是operator new[])分配一块足够大的,原始的,未命名的内存空间以便存储特定类型的对象。
  • 第二步:编译器运行相应的构造函数以构造对象,并为其传入初值。
  • 第三部:对象构造完成后,返回一个指向该对象的指针。

使用delete操作符来释放对象内存时会经历两个步骤:

  • 第一步:调用对象的析构函数。
  • 第二步:编译器调用operator delete(或operator delete[])函数释放内存空间。

总之来说,new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。

new 和 delete的执行过程

可以知道,new实际上是调用了malloc的,delete实际上是调用了free的

new[count]会传入一个int大小(4个字节)的数count进去,使用malloc时就会malloc(count*sizeof(class))

而new是直接malloc(sizeof(class))

delete同理

根据llw大佬的博客简单做个实验分析一下 new/new[] 和 delete/delete[],倘若new[]后用的是delete而不是delete[] 的话,如果函数中有虚表指针,那么可能会删除虚表指针而导致的内存泄漏,如果没有虚表指针的话,可能会进入一个非常大的删除循环中,delete[count]中的count可能是内存中的某一块区域,这个数字特别大时,就会导致进入一个非常大的循环中

malloc的底层干了些什么?

Linux底层有两个分配内存的系统调用brk()mmap()

1、brk是将数据段(.data)的最高地址指针_edata往高地址推;

2、mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存

虚拟内存:让程序以为自己是运行在一块连续内存空间上的程序,实际内存分配还要看伙伴系统

Linux规定

一、malloc小于128k的内存,使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系),如下图:

A=malloc(30K)

B=mallco(40K)

img

​ 缺页中断:

当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作
**1、检查要访问的虚拟地址是否合法 **

**2、查找/分配一个物理页 **

**3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干) **

4、建立映射关系(虚拟地址到物理地址)

二、malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0),如下图:

C=malloc(200K)

img

当释放内存时,大于128K的内存是直接释放

小于128K的内存释放后是可以重用的

当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)

参考:

https://blog.csdn.net/yusiguyuan/article/details/39496057

原文地址:https://www.cnblogs.com/buerdepepeqi/p/12459119.html