在流行的实现中,C和C++中的动态内存分配是否不同?

Ker*_* SB 56 c c++ memory-management

就各自的语言标准而言,C仅通过malloc()族提供动态内存分配,而在C++中,最常见的分配形式是由::operator new().C风格的malloc也有C++版本,许多"baby的第一个分配器"示例使用它作为其核心分配函数,但我很好奇当代编译器如何实现实际的生产操作符 - new.

它只是一个薄的包装器malloc(),或者由于与典型的C程序相比,典型的C++程序的内存分配行为有很大不同,它是否会根本不同地实现?

[ 编辑:我认为主要区别通常描述如下:AC程序具有更少,更大,更长寿的分配,而C++程序具有许多小的短期分配.如果错误的话,请随意加入,但听起来有人会考虑到这一点.

对于像GCC这样的编译器,只需要一个单独的核心分配实现并将其用于所有相关语言就很容易,因此我想知道在每种语言中尝试优化分配性能的细节是否存在差异.


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

NPE*_*NPE 48

以下是使用的实现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;
}
Run Code Online (Sandbox Code Playgroud)

这可以在libstdc++-v3/libsupc++/new_op.ccg ++源代码发行版中找到.

正如你所看到的,它是一个相当薄的包装器malloc.

编辑在许多系统上malloc,通常可以通过调用mallopt或设置环境变量来微调其行为.这是一篇讨论Linux上可用功能的文章.

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

在编写了一些几乎完全依赖于分配动态内存的C++程序之后,我编写了第一个分配器版本.我发现它们的运行速度要慢得多,而且内存消耗总量比我预期的要多得多.这是由于我运行的系统上的内存分配器的特性(主要是当时版本的SunOs和BSD).为了解决这个问题,我首先在C++中编写了许多专用分配器,通常是通过为各种类重载operator new.其中一些在关于C++分配技术的论文中有所描述,该论文已被改编成1989 C++ Report文章的容器类的一些存储分配技术.

但是,我很快就意识到,在构建当时正在编写的各种通用编程支持类时,为每个新类构建一个特殊的分配器,这些类往往是动态分配和大量使用的,这不是一个好的策略.(从1986年到1991年,我是libg ++的主要作者,GNU C++库.)需要一个更广泛的解决方案 - 在正常的C++和C加载下编写一个足够好的分配器,这样程序员就不会想要编写专用分配器,除非在非常特殊的条件下.

本文介绍了此分配器的一些主要设计目标,算法和实现注意事项.

  • @Emilio:我指的是`malloc()`使用的内部分配算法.你看,可能是`malloc()`被调整为对C类型的分配表现良好,但实际上会导致很多碎片或页面错误或C++容器使用时的东西(仅作为示例).所以我的问题是,是否或如何能够使用有关语言典型需求的知识来改进核心分配器的设计.(显然海湾合作委员会没有.) (3认同)

sha*_*oth 15

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


cyc*_*130 12

glibc new operator是malloc的一个薄包装器.glibc malloc对不同的大小分配请求使用不同的策略.您可以在此处查看实施或至少注释.

以下是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 (i.e. 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.
*/
Run Code Online (Sandbox Code Playgroud)


In *_*ico 10

在Visual C++中,单步执行new表达式会引导我进入以下代码段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);
        }
Run Code Online (Sandbox Code Playgroud)

所以VC++ new也包含了这个malloc()电话.