【问题标题】:vector::reserve() appears to not allocate spacevector::reserve() 似乎没有分配空间
【发布时间】:2011-01-24 18:58:57
【问题描述】:

附加代码包含三个对 std::vector::assign() 的调用。在第一次调用之前,调用 std::vector::reserve() 以分配适当的内存量,然后填充向量。在填充第二个向量之前,对 assign() 的第二次调用不会调用 reserve(),因此我希望在调用 assign() 期间至少会发生一次分配。第三次调用 assign() 用于用新数据重新填充第一个向量。代码中的第四个块使用 new 分配一个 int 数组并填充它。

我希望第一个、第三个和第四个块的性能相同,而第二个块由于需要分配而需要额外的时间。我实际发现的是,第一个和第二个块花费相同的时间,而第三个和第四个块的运行速度明显更快(~30%)。在我看来,对 reserve() 的调用实际上并没有分配所需的空间,而是将分配推迟到对 assign() 的调用。

我已经在两个平台上对此进行了测试:使用 Visual C++ 2010 编译器编译的 Windows Vista,以及使用 gcc 4.3.2 编译器编译的 SUSE linux。我尝试了不同级别的优化(包括没有优化),并继续看到相同的行为。任何想法为什么 reserve() 没有按照我的预期做?如果我看到的是正确的行为,那么 reserve() 有什么意义?

谢谢, 乔什

#include <vector>
#include <time.h>
#include <stdio.h>
#include <iostream>

int main()
{
  int     len=1E8, nloops=100;
  clock_t start, stop;
  double  wr=0.0, wor=0.0, wc=0.0, pb=0.0;

  printf("Number of values tested = %d\n", len);
  printf("Number of loops = %d\n", nloops);

  std::vector<int> vec1a, vec1b;
  for(int i=0; i<len; i++) vec1a.push_back(i);
  for(int i=len; i>0; i--) vec1b.push_back(i);

  for(int i=0; i<nloops; i++)
  {
    std::vector<int>  vec2, vec3;
    int              *vec4;

//First block
    vec2.reserve(len);
    start = clock();
    vec2.assign(vec1a.begin(), vec1a.end());
    stop = clock();
    wr += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Second block
    start = clock();
    vec3.assign(vec1a.begin(), vec1a.end());
    stop = clock();
    wor += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Third block
    vec2.clear();
    start = clock();
    vec2.assign(vec1b.begin(), vec1b.end());
    stop = clock();
    wc += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Fourth block
    start = clock();
    vec4 = new int[len];
    for(int j=0; j<len; j++) vec4[j] = vec1a[j];
    stop = clock();
    pb += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));
    delete []vec4;
  }

  printf("With reserve()    = %10.4lE\n", wr);
  printf("Without reserve() = %10.4lE\n", wor);
  printf("With clear()      = %10.4lE\n", wc);
  printf("newed int array   = %10.4lE\n", pb);

  return 0;
}

【问题讨论】:

  • 我正在尝试分析它,但它使用了超过 250 MB 的堆内存。为什么不尝试使用更少的元素但更多的循环?
  • @sbi: ^^ 发生在我们最好的人身上:P
  • 我尝试了不同级别的优化(包括不优化)。不过,我只尝试过发布。
  • @baris_a:对我来说它已经超过 1.5GB,但如果你没有那么多 RAM,为什么不干脆换len
  • 糟糕 - 标题错了,它也在 VC 中。很抱歉!

标签: performance stl


【解决方案1】:

考虑到向量的源代码都在头文件中,您可以搜索 .assign 的作用。在 assign 内部,它一次分配所需数量的项目。模板足够聪明,知道在你做vec2.assign(vec1a.begin(), vec1a.end())时它需要1E8

如果你真的想测试它,遍历每个项目并使用 push_back 而不是 assign()

加法

澄清一下,在 .assign() 的调用堆栈中,它计算新容量并调用 _Grow_to (MSVC++10)。实际上, .assign() 做了一个保留。

【讨论】:

  • 另外,vec2.clear()不一定会释放任何内存,它可以将size()设置为0而不减少capacity()
  • @Ben:IIRC,我什至见过一些看起来很可靠的论点,clear() 不能 释放内存。它应该能够,但是(记住,IIRC)还有一些其他要求可能会在/如果它这样做时被违反。
  • 我使用 clear() 是为了清空内容,但保证下次我尝试用数据填充内存时分配内存。
  • @Josh:使用vec2.swap(std::vector&lt;int&gt;()) 释放向量的容量。
  • @sbi: using vec2.swap(std::vector()) 如您所说,显示的结果与原始代码中的块 1 和 2 相同。再一次,这似乎表明调用 reserve() 什么也没做。我说的对吗?
【解决方案2】:

这并不能解释您的结果,但您可能想知道reservenew[] 都没有实际分配内存。相反,它们只是在您的进程中分配地址空间,只有当它们被使用时,虚拟内存管理器才会提交实际的 RAM 页面(并且页面将一次提交一个,块的一部分可能是承诺和部分不)。

【讨论】:

  • 有趣,我不知道这一点。
  • 这确实解释了我的部分结果:为什么第一次填充向量比第二次填充它慢。感谢您的洞察力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 2018-11-10
  • 2020-09-22
相关资源
最近更新 更多