为什么分配堆内存比分配堆栈记忆更快

Why is allocating heap-memory much faster than allocating stack-memory?

本文关键字:分配 记忆 堆栈 内存 为什么      更新时间:2023-10-16

我试图在堆中分配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;
}

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

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

速度的差异是由于初始化。

要比较堆栈中需要分配数组的堆栈速度:

int data[1e7];

但要警告:很有可能会失败,因为堆栈还不够大,以使其大。

我只是一个初学者,但让我主要理解的是要测试自己。

int *p = new int[1e7];

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

vector<int> v(1e7);

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

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

但是您的示例有另一个问题:也许它甚至无法衡量您的想法。C 中的基准不优化的代码几乎毫无意义,并且正确定时优化代码很难。

让我们看一下您的(修改以获取可读性的(示例,由Clang和-O3优化级别:Godbolt链接。

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
}

编译为:

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

第一部分甚至不会致电新运营商!编译器浏览了您的程序,并意识到您从未使用过分配的数组,因此它从结果可执行文件中删除了分配。

因此,您程序的第一部分在编译以下设置时完全不会在堆上分配数组。

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

我想注意,堆栈分配在运行时绝对没有时间;所有工作都是由编译器完成的。无论优化如何,比较都是没有意义的。