new/delete、malloc/free底层实现剖析和区别

new和malloc的区别

  1. malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
  2. new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。
    malloc/free没有构造函数和析构函数,应尽量使用new/delete。

new和delete与malloc和free不能混在一起使用,对于一个用new获取来的指针调用free,或者对于一个malloc获取来的指针调用delete,其后果是不可预测的。不可预测是指:在开发的阶段工作良好,在测试阶段工作良好,但也可能会最后在使用的过程中出错。

new和delete要采用相同的形式。new对应的是delete,new[]对应的是delete[]。

string *ptr1=new string;
string *ptr2=new string[100];

delete ptr1;//删除一个对象
delete[] ptr2;//删除对象数组

new底层实现过程:

1.内存被分配(通过operator new函数)
2.为被分配的内存调用一个或多个构造函数

operator new伪代码:

void *operator new(size_t size)//operator new可能还有其他参数
{
  if(size == 0)
     size = 1;//处理0字节请求时,把它当做1个字节请求进行处理

  while(1){
   分配size字节内存
   if(分配成功)
     return (指向内存的指针);

   //如果分配不成功
   new_handler globalHandler = set_new_handler(0);//卸除new_handler
   set_new_handler(globalHandler);

  if(globalHandler)
    (*globalHandler)();
  else
    thow std::alloc();//指向出错处理的函数指针为空,抛出异常
  }
}

operator new底层所做的工作:

1.调用set_new_handler函数,输入参数为X的出错处理函数。使得X的new_handler函数成为全局new_handler函数。(标准set_new_handler函数存在于std空间)。

2.调用全局的operator new分配内存。如果一次分配失败,全局的operator new会调用X的new_handler(new_handler函数是全局的),如果全局的new_handler最终未能分配到内存, new_handler抛出std::bad_alloc异常,X的operator new会捕捉到它。X的operator new然后会恢复最初被取代的全局new_handler函数,最后以抛出异常返回。

3.假设全局operator new为类型X的对象分配内存成功,X的operator new会再次调用标准set_new_handler函数来恢复最初的全局出错处理函数,最后返回分配成功的内存的指针。

operator new内部包含一个无限循环,跳出循环的办法有4种,分别为:得到了更多的可用内存、安装了一个新的new_handler(出错处理函数)、卸除了new_handler,抛出了一个std::bad_alloc或其派生类型的异常、返回失败。

operator new在无法完成内存分配请求时,会在抛出异常之前调用客户指定的一个出错处理函数new_handler函数。
指定出错处理函数时要用到set_new_handler函数,在头文件大致是这样定义的:

typedef void (*new_handler());
new_handler set_new_handler(new_handler p)
{
  throw();
}

我们可以看出,new_handler是一个自定义的函数指针类型,指向一个没有输入参数也没有返回值的函数。set_new_handler则是一个输入并返回new_handler类型的函数。

set_new_handler的输入参数是operator new分配内存失败时要调用的出错处理指针,返回值是set_new_handler没调用之前就已经在起作用的旧的出错处理函数的指针。

operator new不能满足内存分配要求时,new_handler函数不只调用一次,而是不断重复,直到找到足够的内存。

一个设计好的new_handler必须满足下面条件的一个。

1.产生更多的可用内存。采取的措施是:在程序启动时分配一个大的内存块,然后在第一次调用new_handler时释放。释放是伴随一些对用户的警告信息。

2.安装另一个不同的new_handler函数。通过调用set_new_handler安装。

3.卸除new_handler。即传递空指针给set_new_handler,若没有安装new_handler,operator new分配内存不成功时就抛出一个标准的std::bad_alloc类型的异常。

4.抛出std::bad_alloc或从std::bad_alloc继承的其他类型的异常。这样的异常不会被operator new捕捉,会被送到最初进行内存请求的地方。

5.没有返回。典型做法就是调用abort或exit。

delete底层实现过程:

1.为将被释放的内存调用一个或多个析构函数
2.释放内存(通过operator delete函数)

析构函数里对指针成员调用delete,原因是增加一个指针成员会做下边的几项工作:
1.在每个构造函数里对指针进行初始化。对于一些构造函数,如果没有内存要分配给指针的话,指针需要初始化为空指针。
2.删除现有内存,通过赋值操作符分配给指针新的内存。
3.在析构函数里删除指针。

如果在构造函数中忘记初始化某个指针,或者在赋值操作的过程中忘记处理,问题很快就会出现,程序出错。但是要是忘记在析构函数中删除指针,不会立即出错,只能表现为一点的内存泄露,并不断的增长,最后占用所有的内存导致程序挂掉。所以,一定要注意,析构函数对指针必须使用delete。

总结:

malloc/free 和 new/delete的区别?

相同点:都是从堆上申请空间,用户需要自己来管理。
不同点
1.所属语言
new是C++特性,malloc是C的。C++一般使用的new,但也可以使用malloc,而C用malloc、realloc、calloc。
2.申请释放方式
new和delete,malloc和free配对使用。new的使用比malloc简单,内部已经实现了大小的计算、类型转换等工作,而malloc使用时需要计算大小及进行类型转换。
3.malloc是标准库函数,new是C++的运算符。
new可以被重载,但malloc不可以,malloc需要库函数的支持,new不需要。
4.构造与析构
new和delete会自动调用构造函数和析构函数,但是malloc和free不会。
5.申请内存失败
申请内存失败,默认new抛出异常,malloc返回NULL。
6.重新分配内存
malloc可利用realloc重新分配内存,new不可以。
7.类型安全性
new会检查类型是否对应,如果不对应会保存,但malloc只关注申请内存的多少,不会检查类型。
8.类型转换
malloc返回的类型是void,所以在调用malloc时要进行显式的类型转换,将void转换成所需的指针类型,new不需要。
9.数组分配
new有明确的方式处理数组的分配,即new[],释放也有delete[],malloc没有。
10.设置内存分配器
new可以设置自己的内存分配器,malloc不可以。

底层做的工作:

1.new T类型

(1)调用operator new(sizeof(T)),该函数的函数原型为void* operator new(size_t size)。
(2)调用operator new中的malloc(set_new_handle),如果申请成功,返回;申请失败(可能原因是内存空间不足),采取应对措施set_new_handler,如果应对措施没有,抛出一个异常。
(3)调用一个构造函数。构造函数显示给出,编译器自动合成。

2.delete p

(1)调用一个析构函数。
(2)调用operator delete,释放空间地址。
(3)调用free函数。

3.new T[N]

(1)调用operator new[] (N*sizeof(T)),会在申请的空间的头部多给4个字节的空间,用来存放N。
(2)调用operator new函数
(3)调用malloc函数
(4)调用N次构造函数,构造出来N个对象。
(5)返回第一个对象所在的首地址,不是原空间的地址,而是原空间的地址向后偏移4个位置。

4.delete[] p

(1)取出N(在空间的前四个字节中)。

*((int*)p-1)
*[(int*)((int)p-4)]

(2)调用N次析构函数。
(3)调用operator delete[] (p)。
(4)调用operator delete。
(5)调用free函数。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值