在stream行的实现中,dynamic内存分配在C和C ++中是不同的?

就各自的语言标准而言,C只能通过malloc()系列提供dynamic内存分配,而在C ++中,最常见的分配forms是由::operator new()来执行的。 C风格的malloc也可以在C ++中使用,许多“宝贝的第一个分配器”的例子使用它作为它的核心分配function,但我很好奇当代编译器如何实现实际的生产运营商 – 新。

它只是一个围绕malloc()简单包装,或者由于与典型的C程序相比,典型的C ++程序存在相当不同的内存分配行为,所以它在本质上是不同的?

[ 编辑:我认为主要区别通常描述如下:AC程序有更less,更大,更长期的分配,而C ++程序有很多,小,短期的分配。 如果这是错误的,可以随意join,但是听起来好像考虑到这一点会受益。]

对于像GCC这样的编译器来说,只需要一个单独的核心分配实现并且将其用于所有相关的语言就很容易,所以我想知道是否在细节上有差异,试图优化每种语言的结果分配性能。


更新:感谢所有伟大的答案! 它看起来像在GCC这完全由ptmalloc解决,MSVC也使用malloc的核心。 有谁知道MSVC-malloc是如何实现的?

这是g++ 4.6.1使用的实现:

 _GLIBCXX_WEAK_DEFINITION void * operator new (std::size_t sz) throw (std::bad_alloc) { void *p; /* malloc (0) is unpredictable; avoid it. */ if (sz == 0) sz = 1; p = (void *) malloc (sz); while (p == 0) { new_handler handler = __new_handler; if (! handler) #ifdef __EXCEPTIONS throw bad_alloc(); #else std::abort(); #endif handler (); p = (void *) malloc (sz); } return p; } 

这可以在g ++源代码发行版的libstdc++-v3/libsupc++/new_op.cc

正如你所看到的,这是malloc的一个相当薄的包装。

编辑在许多系统上,可以通过调用mallopt或设置环境variables来微调malloc的行为。 这里有一篇文章讨论Linux上的一些function。

根据维基百科 , glibc版本2.3+使用分配器的修改版本称为ptmalloc ,它本身是由Doug Leadevise的dlmalloc的衍生物。 有趣的是,在一篇关于dlmalloc的文章dlmalloc Doug Lea给出了以下的观点(重点是我的):

在编写几乎完全依赖分配dynamic内存的C ++程序之后,我写了第一个分配器的版本。 我发现他们的运行速度要慢得多,而且总的内存消耗要比我预期的多得多。 这是由于我运行的系统上的内存分配器的特性(主要是当时的SunO和BSD版本)。 为了解决这个问题,起初我用C ++编写了一些特殊用途的分配器,通常是通过重载operator new来重载各种类。 其中的一些描述在一篇关于C ++分配技术的论文中,该技术已被修改为1989年的C ++报告文章。一些容器类的存储分配技术。

不过,我很快就意识到,为每一个新的类设置一个特别的分配器,这个分配器往往是dynamic分配和大量使用的,在我编写当时编写的各种通用编程支持类时,并不是一个好策略。 (从1986年到1991年,我是GNU C ++库libg ++的主要作者)。需要一个更广泛的解决scheme – 编写一个在正常C ++和C加载下足够好的分配器,这样程序员就不会被诱惑编写特殊用途的分配器,除非在特殊条件下。

本文介绍了该分配器的一些主要devise目标,algorithm和实现注意事项。

在大多数实现中, operator new()只是调用malloc() 。 事实上,即使“标准”也build议将其作为默认策略 。 当然,你可以实现自己的operator new ,如果你想要更好的性能,通常是为了一个类,但是默认情况下通常只是调用malloc()

glibc new运算符是malloc的一个薄包装器。 而glibc malloc针对不同的大小分配请求使用不同的策略。 你可以看到这个实现,或者至less是这里的注释。

下面是从malloc.c中的注释摘录:

 /* 47 This is not the fastest, most space-conserving, most portable, or 48 most tunable malloc ever written. However it is among the fastest 49 while also being among the most space-conserving, portable and tunable. 50 Consistent balance across these factors results in a good general-purpose 51 allocator for malloc-intensive programs. 52 53 The main properties of the algorithms are: 54 * For large (>= 512 bytes) requests, it is a pure best-fit allocator, 55 with ties normally decided via FIFO (ie least recently used). 56 * For small (<= 64 bytes by default) requests, it is a caching 57 allocator, that maintains pools of quickly recycled chunks. 58 * In between, and for combinations of large and small requests, it does 59 the best it can trying to meet both goals at once. 60 * For very large requests (>= 128KB by default), it relies on system 61 memory mapping facilities, if supported. */ 

在Visual C ++中,进入一个newexpression式,引导我到new.cpp这个片段:

 #include <cstdlib> #include <new> _C_LIB_DECL int __cdecl _callnewh(size_t size) _THROW1(_STD bad_alloc); _END_C_LIB_DECL void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) if (_callnewh(size) == 0) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); } return (p); } 

所以VC ++的new包也包装了malloc()调用。

这不是性能问题: pA = new ApA = (A*)malloc(sizeof(A));有不同的副作用pA = (A*)malloc(sizeof(A));

在第二个,A的构造函数不被调用。 为了达到同样的效果,你应该这样做

 pA = (A*)malloc(sizeof(A)); new(pA)A(); 

新的是“新的安置”…

 void* operator new(size_t sz, void* place) { return place; }