new/delete & malloc/free

new&delete

1、new简单类型直接调用operator new分配内存;而对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;对于简单类型,new[]计算好大小后调用operator new;对于复杂数据结构,new[]先调用operator new[]分配内存,然后在 p 的前四个字节写入数组大小 n,然后调用 n 次构造函数,针对复杂类型,new[]会额外存储数组大小;

  ① new表达式调用一个名为operator new(operator new[])函数,分配一块足够大的、原始的、未命名的内存空间;

  ② 编译器运行相应的构造函数以构造这些对象,并为其传入初始值;

  ③ 对象被分配了空间并构造完成,返回一个指向该对象的指针

2、delete 简单数据类型默认只是调用 free 函数;复杂数据类型先调用析构函数再调用 operator delete;针对简单类型,delete 和 delete[]等同。假设指针 p 指向new[]分配的内存。因为要 4 字节存储数组大小,实际分配的内存地址为[p-4],系统记录的也是这个地址。delete[]实际释放的就是p-4指向的内存。而delete会直接释放p指向的内存,这个内存根本没有被系统记录,所以会崩溃。

3、需要在 new [] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了。

 

operator new、operator delete、placement new、placement delete

1) new operator

new operator 完成了两件事情:用于申请内存和初始化对象。

例如:string* ps = new string("abc");

2) operator new

operator new 类似于C语言中的malloc,只是负责申请内存。

例如:void* buffer = operator new(sizeof(string)); 注意这里new前要有个operator

3) placement new布局new:用于在给定的内存中初始化对象。

例如:void* buffer = operator new(sizeof(string));buffer = new(buffer) string("abc"); 调用了placement new,在buffer所指向的内存中创建了一个string类型的对象并且初始值为“abc”。

4) 因此可以看出:new operator 可以分解operator new 和 placement new两个动作,是 operator new 和 placement new 的结合。与new对应的delete没有 placement delete 语法,它只有两种,分别是delete operator 和 operator delete。delete operator 和 new operator 对应,完成析构对象和释放内存的操作。而 operator delete 只是用于内存的释放,与C语言中的free相似

 

malloc&free

1、在标准 C 库中,提供了 malloc/free 函数分配释放内存,这两个函数底层是由 brk、mmap、,munmap这些系统调用实现的;

2、brk 是将数据段(.data)的最高地址指针_edata 往高地址推,mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系;

3、malloc小于128k的内存,使用brk分配内存,将_edata往高地址推;malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配;brk分配的内存需要等到高地址内存释放以后才能释放,而 mmap 分配的内存可以单独释放。当最高地址空间的空闲内存超过 128K(可由 M_TRIM_THRESHOLD 选项调节)时,执行内存紧缩操作(trim)。在上一个步骤 free 的时候,发现最高地址空闲内存超过 128K,于是内存紧缩。

4、malloc是从堆里面申请内存,也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

区别:

1、new/delete 是 C++关键字,需要编译器支持,可重载。malloc/free 是库函数,需要头文件支持,可以重写;

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

3、new 操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故 new 是符合类型安全性的操作符。而 malloc 内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

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

5、new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free 是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。malloc申请的存储空间也不能用delete释放,malloc /free 的操作对象都是必须明确大小的。而且不能用在动态类上。new 和delete会自动进行类型检查和大小,malloc/free不能执行构造函数与析构函数,所以动态对象它是不行的。且不保证在C++上运行成功。

 

delete p与 delete[]p,allocator

1、动态数组管理new一个数组时,[]中必须是一个整数,但是不一定是常量整数,普通数组必须是一个常量整数;

2、new动态数组返回的并不是数组类型,而是一个元素类型的指针;

3、delete[]时,数组中的元素按逆序的顺序进行销毁;

4、new在内存分配上面有一些局限性,new的机制是将内存分配和对象构造组合在一起,同样的,delete也是将对象析构和内存释放组合在一起的。allocator将这两部分分开进行,allocator 申请一部分内存,不进行初始化对象,只有当需要的时候才进行初始化操作。

posted @ 2021-08-29 22:17  默行于世  阅读(27)  评论(0编辑  收藏  举报