C与C ++在内存分配方面的表现

时间:2010-03-25 07:34:27

标签: c++ c performance memory-management

我计划参与开发用C语言编写的代码,用于蒙特卡罗对复杂问题的分析。这段代码在内存中分配了巨大的数据数据以加速其性能,因此代码的作者选择了C而不是C ++声称可以使用C来制作更快,更可靠(关于内存泄漏)的代码。

你同意吗?如果您需要在计算期间将4-16 GB的数据阵列存储在内存中,您会选择什么?

8 个答案:

答案 0 :(得分:22)

绝对是C ++。默认情况下,两者之间没有显着差异,但是 C ++提供了C不提供的一些东西:

  1. 构造/析构函数。这些可以让您自动化大多数内存管理,提高可靠性。
  2. 每班分配器。这些允许您根据特定对象的设计和/或使用方式来优化分配。如果您需要大量小对象(这是一个明显的例子),这可能特别有用。
  3. 最重要的是,在这方面,C绝对不可能比C ++更具优势。在最糟糕的情况下,你可以用同样的方式做同样的事情。

答案 1 :(得分:8)

C99中有一个功能,它不存在于C ++中,并且可能会在繁重的数字运算代码中显着提高速度,这就是关键字restrict。如果您可以使用支持它的C ++编译器,那么在优化时您可以在套件中使用额外的工具。但这只是一个潜在的收获:足够的内联可以允许与restrict或更多相同的优化。它也与内存分配无关。

如果代码的作者可以证明C和C ++代码分配4-16GB阵列之间的性能差异,那么(a)我很惊讶,但是好的,有区别,(b)有多少是要分配这么大的数组的程序吗?您的程序实际上是否会花费大量时间来分配内存,还是花费大部分时间访问内存并进行计算?与分配时间相比,实际任何具有4GB阵列的东西需要很长时间,这意味着您应该担心“任何事情”的表现,而不是分配的性能。短跑运动员非常关心他们下车的速度有多快。马拉松运动员,不是那么多。

您还必须小心如何进行基准测试。您应该将malloc(size)new char[size]进行比较。如果你对malloc(size)测试new char[size]()那么这是一个不公平的比较,因为后者将内存设置为0而前者不设置。与calloc进行比较,但请注意,malloccalloc都可以在(不太可能的)事件中从C ++获得,它们确实可以显着提高速度。

但是,最终,如果作者“拥有”或启动该项目,并且更喜欢用C而不是C ++编写,那么他不应该用可能虚假的性能声明来证明这个决定,他应该通过说“我更喜欢C,这就是我正在使用的“。通常,当有人就这种语言表现做出这样的声明,并且结果证明测试不是真的时,您会发现表现并不是语言偏好的真正原因。证明声明错误实际上不会导致该项目的作者突然开始喜欢C ++。

答案 2 :(得分:3)

在内存分配方面,C和C ++之间没有真正的区别。如果您选择在对象上使用虚拟方法,则C ++具有更多“隐藏”数据,例如虚拟指针等。但是在C中分配一个字符数组和在C ++中一样昂贵,事实上,它们可能都使用malloc来实现它。在性能方面,C ++为数组中的每个对象调用一个构造函数。请注意,只有在存在一个时,才会执行此操作,默认构造函数不执行任何操作并进行优化。

只要您预先分配数据池,以避免内存碎片,您应该好好去。如果你有没有虚拟方法的简单POD结构,没有构造函数,那就没有区别了。

答案 3 :(得分:3)

唯一不喜欢C ++的是它的额外复杂性 - 将它与错误使用它的程序员结合起来,你可以很容易地显着减慢速度。使用没有C ++功能的C ++编译器可以提供相同的性能。正确使用C ++,你有一些能力更快。

语言不是您的问题,分配和遍历大型数组是。

你可以在分配中使用的主要致命错误(使用任何一种语言)分配16G内存,将其初始化为零,只是稍后用实际值填充它。

我希望通过算法优化获得最大的性能提升,从而提高参考的局部性。

根据底层操作系统,您可能还会影响缓存算法 - 例如表示只按顺序处理一系列memroy。

答案 4 :(得分:2)

对于分配原始数据,在大多数系统上C和C ++之间应该没有区别,因为它们通常都使用相同的运行时库机制。我想知道这是否是经典的基准陷阱,他们还测量了C ++中构造函数调用的运行时间,并且方便地忘记了在C中包含任何类型的初始化代码的运行时。

此外,如果你在C ++中使用RAII,那么“更可靠(关于内存泄漏)”的论点并没有任何用处(如你所愿)。除非有人提到使其更可靠地泄漏,否则使用RAII,智能指针和容器类将减少泄漏的可能性,而不是增加泄漏。

我主要关心分配那么多内存将是双重的:

  • 如果您正在接近正在运行蒙特卡罗模拟的计算机上的物理内存限制,这是降低性能的好方法,因为当虚拟内存系统需要启动时磁盘可能会开始抖动分页很多。即使很多人都认为,虚拟内存并非“免费”。
  • 需要仔细考虑数据布局以最大限度地提高处理器缓存的使用率,否则您将部分失去将数据保存在主内存中的好处。

答案 5 :(得分:1)

如果内存分配是此类代码中的瓶颈,我建议重新设计,而不是更改语言以便更快地进行分配。如果您分配一次内存然后执行大量计算,我希望这些计算成为瓶颈。如果分配成本很高,这里有些问题。

答案 6 :(得分:0)

您也可以在C ++中使用C系列内存分配函数:标准mallocfreerealloc放大/分组数组和alloca分配堆栈中的内存。

如果你使用new,它将分配比所需更多的内存(主要是在调试期间),并进行额外的一致性检查。它还将为类调用构造函数。在发布版本(-O3)中,对于大多数应用程序而言,差异可以忽略不计。

现在new带来的malloc不是就地new。您可以预先分配一个缓冲区,然后使用就地new将您的结构放入该缓冲区,从而立即“分配”它。

总而言之,由于性能问题,我不会远离C语言。如果有的话,你的代码将更有效,因为类在寄存器中传递this指针,而不是像C等价物中那样的参数。远离C的真正原因是C ++运行时的大小。如果您为嵌入式系统或启动加载的程序开发程序,则无法嵌入~4mb运行时。然而,对于正常的应用程序,这不会产生任何影响。

答案 7 :(得分:0)

如果你需要在计算过程中将4-16 GB的数据阵列存储在内存中,而你的机器只有2GB的物理内存,那么呢?

如果您的机器有16GB的物理内存怎么办?操作系统是否不占用物理内存?

操作系统是否甚至允许您使用4GB,16Gb等地址空间?

我建议,如果性能是一个主要的实现约束,那么了解如何使用,运行和执行的平台比在相同环境下C和C ++之间任何可衡量的性能差异的问题更重要和算法。