堆上分配的数据访问速度是不是比栈上分配的数据慢?

Posted

技术标签:

【中文标题】堆上分配的数据访问速度是不是比栈上分配的数据慢?【英文标题】:Is data allocated on the heap slower to access than data allocated on the stack?堆上分配的数据访问速度是否比栈上分配的数据慢? 【发布时间】:2017-11-25 14:51:55 【问题描述】:

我在这件事上听到了相互矛盾的意见。

有人说访问堆上分配的数据(即std::vector或通过malloc分配的动态数组)总是比访问堆栈上分配的数据慢一点,因为进程必须总是通过一个中间指针才能访问该数据可能位于完全不同的内存区域;另一方面,他们维护,访问分配在堆栈上的数据不需要通过这个中间指针,而且这些数据很可能已经被缓存了。

其他人声称只有在堆上的数据分配比在堆栈上慢(因为 mallocmmap 和类似函数的开销),但访问不是,除了堆栈时的极少数情况并且堆位于不同的物理驱动器上。

真相是什么?

【问题讨论】:

没有真相。这取决于您的整个系统 - 代码和硬件。 NUMA machines 上的情况更加复杂。如果您确实需要了解,请分析您的应用程序并对其进行测试。 Err,堆栈和堆都没有与物理驱动器关联。 当内存访问转到“交换”(通常在物理驱动器上)时,您的代码不再“快速”,既不是堆栈也不是堆。 “我在这件事上听到了相互矛盾的意见。” - 关于所有你可以期待的。这两者怎么可能是真理? 参考位置是现代处理器的一切,L1 缓存中的数据访问速度很快,其他一切都很匆忙。堆栈总是占据优势,因为由于堆栈指针,它总是很热,编译器自然地对可能的访问进行分组,而且因为它很小,所以很难把你的腿打断。但它很小,照顾性能问题的程序员从不这样做,因为他们正在处理小任务。所以它作为“总是这样做this”的指导并没有多大用处。这是一句老生常谈,只不过是“过马路前左右看看”。 【参考方案1】:

事实(至少在大多数现代 CPU 上)是堆栈和堆的性能相同,因为它们都只是 RAM 的一部分。所以取消引用指针几乎是一样的。

不同之处在于堆栈是为您的进程/线程预先分配的,因此您不需要mallocfree 系统调用来使用它。特别是malloc 是昂贵的。另一个区别是,可能有一些特定的 CPU 指令用于处理堆栈以提高性能(例如,程序集的 pushpop)。然而,这些不太可能与内存访问(如将内存加载到寄存器)本身有任何关系。

另一个区别是,如果您用完堆栈,您的程序将(更有可能)崩溃。而如果你用完了堆,那么你的操作系统可能会使用交换来为你降低数千倍的性能。

缓存未命中当然是一个因素,它更经常发生在堆上,然后是堆栈上。但这仅仅是因为与堆栈相比,堆非常大。但是请注意,缓存未命中并不是那么重要,除非您编写的是 CPU 非常繁重的代码。

现在你是对的,std::vector 必须取消引用附加时间。但是这里缓慢的是取消引用,而不是那些指针在堆栈或堆上。他们在哪里并不重要。双解引用总是比单解引用慢。

现在堆栈和堆也可​​能位于不同的物理设备上。并且这两个设备具有不同的速度(可能堆更快)。但这又与堆栈和堆本身无关。这可能发生在内存的任何两个部分。你真的无能为力。甚至操作系统也不能(好吧,也许可以,我不确定)。是主板的事此外,主板很可能无论如何都会降频更快的设备。

【讨论】:

【参考方案2】:

有人说访问在堆上分配的数据(即 std::vector 或通过 malloc 分配的动态数组)总是比访问在堆栈上分配的数据慢一点,因为进程必须总是通过一个中间指针来访问它数据,可能位于完全不同的内存区域;另一方面,他们维护,访问分配在堆栈上的数据不需要通过这个中间指针,而且这些数据很可能已经被缓存了。

这是牛粪废物。只有静态可以在没有中间指针寄存器的情况下访问。堆栈数据通过寄存器 (SP) 访问,某些处理器具有补充堆栈寄存器(例如,BP、AP)。

此外,记忆就是记忆。使内存成为堆栈的唯一想法是它作为堆栈访问。

其他人声称只有在堆上分配数据比在堆栈上慢(因为 malloc、mmap 和类似函数的开销),但访问不是

这是正确的。在堆栈上分配数据只需要一条指令。

【讨论】:

以上是关于堆上分配的数据访问速度是不是比栈上分配的数据慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要在堆上而不是栈上分配内存? [复制]

动态内存使用速度较慢是啥? [复制]

堆和栈的区别 还有啥建立在堆上 啥建立在栈上

java创建对象时分配内存方式,是堆上分配还是栈上分配?

Go 语言中的变量究竟是分配在栈上还是分配在堆上?

Go 语言中的变量究竟是分配在栈上还是分配在堆上?