为什么new() / delete()比malloc() / free()慢?

19

为什么new()/delete()比malloc()/free()慢?

编辑:

感谢至今为止的回答。如果您拥有标准C++实现new()和delete()的规格,请指出,谢谢!


3
因为将它们进行对比没有意义。相比较,应该将malloc::operator new进行对比,并将free::operator delete对比以得出等价性。 - GManNickG
5个回答

31

看看这段 C 代码:

struct data* pd = malloc(sizeof(struct data));
init_data(pd);

C++ 中的 new 运算符本质上在执行和上面这段代码类似的操作,这就是为什么它比 malloc() 更慢的原因。

delete 也是如此。它在执行相当于以下代码:

deinit_data(pd);
free(pd);
如果构造函数和析构函数是空的(例如内置类型),那么newdelete不应该比malloc()free()慢。(如果它们慢,通常是因为常见的实现在背后调用malloc()/free(),因此它们是其包装器。包装成本很高。另外,可能存在需要确定不需要调用构造函数/析构函数的代码。这也会产生成本。) 编辑回答您的其他问题: newdelete不是函数,它们是操作符。这个:new data()被称为一个new表达式。它做两件事情。首先调用operator new,然后通过调用适当的构造函数初始化对象。(我说“通常”是因为内置类型没有构造函数。但是涉及内置类型的new表达式仍然起作用。)
您可以操纵这两个阶段。可以创建自己的构造函数来操纵类型的初始化,并且可以重载operator new(甚至使用具有不同附加参数的多个重载,每个类都特定地重载,如果需要)以操纵分配自由存储空间。如果未实现自己的operator new,则使用标准库的版本。这个常见的实现调用malloc()
同样,如果您编写delete pd,称为delete表达式,则会发生两件事情:根据pd,对象被取消初始化,通常是通过调用其析构函数来完成,然后通过调用适当的operator delete释放内存。
同样,您可以通过编写自己的析构函数和自己的版本operator delete来操纵这两个阶段。(随附您的标准库的operator delete版本通常是实现为调用free()。)

13

new和delete处理的是构造/析构,其中它们的一部分工作是有效地调用malloc()和free() - malloc()和free()是原始内存分配/释放。


2
因为 newdelete 执行的工作与 mallocfree 相同,并且它们还会调用构造函数/析构函数。除非构造函数/析构函数特别缓慢,否则我不认为会有太大的差异。 - T.J. Crowder

4
如果您使用它们来分配“纯老数据”,使得构造函数/析构函数是微不足道的,那么它们与malloc/free在速度上几乎没有太大区别。您可能(很有可能?)在测量中犯了错误,导致结果有偏差。实际上,除了调用malloc/free外,它们只执行类型的构造函数/析构函数(对于数组而言需要多次执行)。

我尝试过使用 PODs。new() / delete() 仍然慢一些,但差别不是那么明显,只有几个百分点(不到4%)到几千分之一或几万分之一。 - Viet
7
你是否尝试过使用new int()进行测试?这会有所不同,因为后者保证了int被初始化为零,而前者则不进行任何初始化。 - sbi

4
当调用new运算符时,会发生两件事情:
  1. 为堆上的对象分配内存。
  2. 调用对象的构造函数。
因此,由于对象构建的开销,newmalloc慢。
同样,delete做以下两件事:
  1. 调用堆对象的析构函数。
  2. 释放对象的内存。
简而言之,malloc仅分配原始内存,而new不仅分配原始内存,还将原始内存转换为对象。

1

他们不应该被使用,并且在我工作的代码库中也没有使用。

在我的工作环境中,malloc/free比new/delete更慢且效率更低,原因如下:

  • free()不知道对象的大小,而delete通常在编译时就知道了对象的大小。
  • malloc()不知道它正在分配的对象类型,因此它必须始终提供16字节对齐的内存。这通常会造成浪费。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接