访问堆对象与堆栈对象的 C++ 性能

C++ performance of accessing heap vs. stack objects

我知道使用堆对象比较慢,因为需要进行内存管理(分配、释放)。访问它们怎么样?访问堆栈上的对象与访问堆上的对象时有任何性能差异吗?

编辑: 我的问题是 not about allocation 但访问它们。这包括堆栈与堆的内存位置、缓存未命中或我不知道的任何其他变量。用一个简单的玩具示例:

int stack_array[100];
int* heap_array = new int[100];
...
...
std::cout << stack_array[51]; // Any difference between these two statements
std::cout << heap_array[51]; // Any difference between these two statements

除非物理内存不同,否则您可能不会注意到堆栈和堆(动态内存)之间的任何速度差异。

数组的访问是直接的,与内存位置无关。您可以通过查看编译器生成的汇编语言来确认这一点。

如果 OS 决定为您的阵列使用虚拟内存,则可能会有所不同。这意味着 OS 可以将数组的 page 块存储到硬盘驱动器并根据需要将它们换出。

在大多数应用中,如果内存类型之间存在物理差异(在速度方面),则可以忽略不计,以纳秒为单位。对于计算量更大的应用程序(大量数据或需要速度),这可能会有所不同。

但是,还有其他问题使得内存访问不是问题,例如:

  • 磁盘I/O
  • 等待用户输入
  • 内存分页
  • 与其他应用程序或线程共享 CPU

上述所有项目的开销通常比访问内存设备高出一个数量级。

使用动态内存而不是基于堆栈的主要原因是大小。栈内存主要用于传递参数和存储return地址。没有声明为静态的局部变量也会被放入栈中。大多数编程环境给堆栈区域一个较小的尺寸。较大的项目可以放置在堆上或声明为静态(并放置在与全局相同的区域)。

比内存性能更担心正确性。有疑问时进行配置文件。

编辑 1:缓存未命中
Cache Miss 是指处理器在其数据缓存中查找但未找到该项目;然后处理器必须从外部存储器中获取项目(a.k.a。重新加载缓存)。

对于大多数应用程序,缓存未命中在性能上可以忽略不计,通常以小的纳秒值来衡量。除非您的程序计算密集或处理大量数据,否则它们不会引人注意。

分支指令将比高速缓存未命中占用更多的执行时间。一些条件分支指令可能会强制处理器重新加载指令流水线并重新加载程序计数器寄存器。 (注意:一些处理器可以将可执行循环代码拖入指令缓存并减少分支效应的惩罚。)

您可以组织数据以减少缓存未命中的数量。在网络上搜索 "data driven" 或 "data optimizations"。还可以尝试通过应用代数、布尔代数和将不变量分解出循环来减少分支。