【问题标题】:C++, bad performance when instantiating a std::vectorC++,实例化 std::vector 时性能不佳
【发布时间】:2014-12-10 10:50:22
【问题描述】:

我有一个关于 std::vector 实例化的问题。我比较了 std::vector 的实例化和相同大小的数组的动态分配。我原以为 std::vector 的实例化需要更长的时间,但我的性能差异很大。

对于数组,我有 53 个我们 对于 std::vector 我有 4338 我们

我的代码:

#include <chrono>
#include <vector>
#include <iostream>

int main() {
    unsigned int NbItem = 1000000 ;
    std::chrono::time_point<std::chrono::system_clock> start, middle ,end;
    start = std::chrono::system_clock::now() ;
    float * aMallocArea = (float *)calloc(sizeof(float)*NbItem,0) ;
    middle = std::chrono::system_clock::now() ;
    std::vector<float> aNewArea ;
    middle = std::chrono::system_clock::now() ;
    aNewArea.resize(NbItem) ;
    //float * aMallocArea2 = new float[NbItem];
    end = std::chrono::system_clock::now() ;
    std::chrono::duration<double> elapsed_middle = middle-start;
    std::chrono::duration<double> elapsed_end = end-middle;
    std::cout << "ElapsedTime CPU  = " << elapsed_middle.count()*1000000 << " (us) " << std::endl ;
    std::cout << "ElapsedTime CPU  = " << elapsed_end.count()*1000000 << " (us) " << std::endl ;
    free(aMallocArea) ;
    return 0;
}

即使我创建一个大小为 0 的向量,我也有这个区别。 你知道为什么我在实例化 std::vector 时表现如此糟糕吗? 你知道如何改进吗(我尝试使用编译选项 -O3 但它没有给出出色的结果)。

编译行: g++ --std=c++11 -o test ./src/test.cpp

编译器版本: g++ --版本 g++ (Debian 4.7.2-5) 4.7.2 版权所有 (C) 2012 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。没有 保修单;甚至不是为了适销性或特定用途的适用性。

【问题讨论】:

  • std::vector 的第一次实例化可能会产生开销。但是后续的实例化呢?
  • 请提供您的编译器版本和编译命令行。
  • calloc(sizeof(float)*NbItem,0) 这有点奇怪,分配了 0 大小的对象。这不是问题,但我会尝试分配至少 1 的大小,看看它的行为是否有任何不同。
  • 将 0 的大小传递给 calloc 是实现定义的,并且使整个比较完全没有价值,因为它可能只是返回 Null 而无需进行任何分配。见:en.cppreference.com/w/cpp/memory/c/calloc

标签: c++ arrays performance vector stl


【解决方案1】:

你是否意识到这一点:

float * aMallocArea = (float *)calloc(sizeof(float)*NbItem, 0);

表示“分配大小为零的sizeof(float)*NbItem 项目”?这意味着调用执行零字节分配。

即使您纠正了这一点,calloc 表单在许多情况下也会快得多。 calloc 实现能够“保留”一个内存域并返回一个指针。当您访问内存时,操作系统会映射虚拟内存。

另一方面,向量实际上会遍历并初始化/构造其元素。没有实现我知道检查 a) 类型是 POD,b) 内存为零,以及 c) 分配器返回零内存。因此,与calloc 相比,这个初始化过程可能会花费不少。

所以“C”版本几乎什么都不做(如果你修复了你的程序),而“C++”版本会通过,初始化每个元素,并触及分配中的所有内存。会慢很多。

这很少是支持 C 版本的好理由,即使在性能很重要的地方也是如此。在实践中,您应该只分配您实际需要的内存。一旦你开始使用内存做某事,时间就会结束(例如,在 C 版本中,稍后访问内存时需要时间来映射内存)。如果您创建第二个定时测试(例如)计算数组元素的平均值,那么 C++ 版本在您的实现上可能会更快,因为内存已经映射和初始化,而C 版本将在您读取内存时执行映射和初始化。

【讨论】:

猜你喜欢
  • 2022-07-15
  • 2019-07-09
  • 2018-06-06
  • 2012-06-30
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多