为什么分配堆内存比分配堆栈内存快得多?

Oma*_*ser 5 c++ performance heap-memory stack-memory

我尝试为堆和堆栈内存中的10 ^ 7整数分配空间,以查看哪一个更快。显然,在堆内存中分配要快得多,但是我不明白原因。

#include <bits/stdc++.h>
#include <chrono>

using namespace std;
using namespace std::chrono;

int main()
{
  high_resolution_clock::time_point t1 = high_resolution_clock::now();

  int *p = new int[1e7];

  high_resolution_clock::time_point t2 = high_resolution_clock::now();
  auto duration = duration_cast<microseconds>( t2 - t1 ).count();
  cout << duration / 1e6 << "\n"; // 5e-06



  t1 = high_resolution_clock::now();

  vector<int> v(1e7);

  t2 = high_resolution_clock::now();
  duration = duration_cast<microseconds>( t2 - t1 ).count();
  cout << duration / 1e6 << "\n"; // 0.112284

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ker 15

new int[1e7]为1e7 int值分配空间,并且不初始化它们。

vector<int> v(1e7);vector<int>在堆栈上创建一个对象,然后该对象的构造函数为int堆上的1e7 值分配空间。它还将每个int值初始化为0。

速度差异是由于初始化。

要比较堆栈分配的速度,您需要在堆栈上分配一个数组:

int data[1e7];
Run Code Online (Sandbox Code Playgroud)

但请注意:这很有可能失败,因为堆栈不足以容纳那么大的数组。


小智 7

我只是一个初学者,但让我给出我主要了解的内容以测试自己。

int *p = new int[1e7];
Run Code Online (Sandbox Code Playgroud)

您正在堆上为1000万个整数分配连续的内存。

vector<int> v(1e7);
Run Code Online (Sandbox Code Playgroud)

您正在为vector<int>对象分配堆栈内存。在该对象的成员之间,有一个指向int[1e7]堆的指针,该指针也已分配。此外,其中的所有值均以int()(带有0s)的值初始化。参见的构造函数(2)std::vector


Ser*_*kov 5

其他答案指出,向量构造函数中至少有一个“隐藏”初始化。

但是您的示例还有另一个问题:也许它甚至无法衡量您的想法。在C ++中对未优化的代码进行基准测试几乎没有意义,并且很难对优化的代码进行适当的时序调整。

让我们看一下Clang编译的示例(出于可读性的考虑),其-O3优化级别为:godbolt link

double test1() {
  high_resolution_clock::time_point t1 = high_resolution_clock::now();

  int *p = new int[1e7];

  high_resolution_clock::time_point t2 = high_resolution_clock::now();
  auto duration = duration_cast<microseconds>( t2 - t1 ).count();
  return duration / 1e6; // 5e-06
}
Run Code Online (Sandbox Code Playgroud)

编译为:

test1():                              # @test1()
        push    rbx
        call    std::chrono::_V2::system_clock::now()
        mov     rbx, rax
        call    std::chrono::_V2::system_clock::now()
        sub     rax, rbx
        movabs  rcx, 2361183241434822607
        imul    rcx
        mov     rax, rdx
        shr     rax, 63
        sar     rdx, 7
        add     rdx, rax
        cvtsi2sd        xmm0, rdx
        divsd   xmm0, qword ptr [rip + .LCPI0_0]
        pop     rbx
        ret
.LCPI1_0:
        .quad   4696837146684686336     # double 1.0E+6
Run Code Online (Sandbox Code Playgroud)

第一部分甚至不称操作员为新!编译器浏览了您的程序并意识到您从未使用过分配的数组,因此它从生成的可执行文件中删除了分配。

因此,使用此类设置进行编译时,程序的第一部分根本不会在堆上分配数组,从而使测量变得毫无意义。

我建议阅读基准测试,并使用专门的微型基准测试框架进行此类测试。看看Google Benchmark(和在线QuickBench)及其文档。