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)
缺页中断:
当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作:
**1、检查要访问的虚拟地址是否合法 **
**2、查找/分配一个物理页 **
**3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干) **
4、建立映射关系(虚拟地址到物理地址)
二、malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0),如下图:
C=malloc(200K)
当释放内存时,大于128K的内存是直接释放
小于128K的内存释放后是可以重用的
当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)
参考: