为什么在堆上迭代一个大数组比在堆栈上迭代相同大小的数组快
Why is iterating a large array on the heap faster than iterating same size array on the stack?
我正在分配两个相同大小的数组,一个在堆栈上,一个堆上,然后用简单的赋值对它们进行迭代。
编译可执行文件为主线程堆栈分配40mb。
此代码仅在带有/STACK:41943040链接器标记的vc++中进行了编译测试。
#include "stdafx.h"
#include <string>
#include <iostream>
#include <malloc.h>
#include <windows.h>
#include <ctime>
using namespace std;
size_t stackavail()
{
static unsigned StackPtr; // top of stack ptr
__asm mov [StackPtr],esp // mov pointer to top of stack
static MEMORY_BASIC_INFORMATION mbi; // page range
VirtualQuery((PVOID)StackPtr,&mbi,sizeof(mbi)); // get range
return StackPtr-(unsigned)mbi.AllocationBase; // subtract from top (stack grows downward on win)
}
int _tmain(int argc, _TCHAR* argv[])
{
string input;
cout << "Allocating 22mb on stack." << endl;
unsigned int start = clock();
char eathalfastack[23068672]; // approx 22mb
auto length = sizeof(eathalfastack)/sizeof(char);
cout << "Time taken in ms: " << clock()-start << endl;
cout << "Setting through array." << endl;
start = clock();
for( int i = 0; i < length; i++ ){
eathalfastack[i] = i;
}
cout << "Time taken in ms: " << clock()-start << endl;
cout << "Free stack space: " << stackavail() << endl;
cout << "Allocating 22mb on heap." << endl;
start = clock();
// auto* heaparr = new int[23068672]; // corrected
auto* heaparr = new byte[23068672];
cout << "Time taken in ms: " << clock()-start << endl;
start = clock();
cout << "Setting through array." << endl;
for( int i = 0; i < length; i++ ){
heaparr[i] = i;
}
cout << "Time taken in ms: " << clock()-start << endl;
delete[] heaparr;
getline(cin, input);
}
输出是这样的:
Allocating 22mb on stack.
Time taken in ms: 0
Setting through array.
Time taken in ms: 45
Free stack space: 18872076
Allocating 22mb on heap.
Time taken in ms: 20
Setting through array.
Time taken in ms: 35
为什么堆栈数组的迭代比堆上相同的东西慢?
编辑:nneonneo咳嗽我的错误
现在输出相同:
Allocating 22mb on stack.
Time taken in ms: 0
Setting through array.
Time taken in ms: 42
Free stack space: 18871952
Allocating 22mb on heap.
Time taken in ms: 4
Setting through array.
Time taken in ms: 41
根据ÖöTiib的以下答案发布构建:
Allocating 22mb on stack.
Time taken in ms: 0
Setting through array.
Time taken in ms: 5
Free stack space: 18873508
Allocating 22mb on heap.
Time taken in ms: 0
Setting through array.
Time taken in ms: 10
您的数组大小不同;CCD_ 1以及这些元件是不同类型的。
您的电脑出现问题,在我的旧版Pentium 4上,分配这样的基于堆栈的字符数组需要15毫秒。你试过调试版本吗?
您的问题有两部分:
- 在堆栈和堆上分配空间
- 访问堆栈上的内存位置与全局可见
分配空间
首先,让我们看看在堆栈上分配空间。我们所知道的堆栈在x86体系结构上向下增长。因此,为了在堆栈上分配空间,您所要做的就是减少堆栈指针。只有一条汇编指令(dec-sp,#amount)。此汇编指令总是出现在函数的序言中(函数设置代码)。所以,据我所知,在堆栈上分配空间一定不会花费任何时间。在堆栈上分配空间的成本=(递减sp运算)。在现代超标量机上,此指令的执行将与其他指令重叠。
另一方面,在堆上分配空间需要对new/malloc进行库调用。库调用首先检查堆上是否有空间。如果是,那么它将只返回一个指向第一个可用地址的指针。如果堆栈上没有可用空间,它将使用brk系统调用请求内核修改附加页面的页面表条目。系统调用是一项成本高昂的操作。它将导致管道刷新、TLB污染等。因此,在堆上分配空间的成本=(函数调用+空间计算+(brk系统调用)?)。毫无疑问,在堆上分配空间似乎比堆栈慢一个数量级。
访问元素x86 ISA的寻址模式允许使用直接寻址模式(temp=mem[addr])对内存操作数进行寻址,以访问全局变量,而堆栈上的变量通常使用索引寻址模式进行访问。(temp=mem[堆栈指针+堆栈上的偏移量])。我的假设是,两个内存操作数应该花费几乎相同的时间。然而,直接寻址模式似乎肯定比索引寻址模式快。关于数组的内存访问,我们有两个操作数来访问任何元素——数组的基址和索引变量。当我们访问堆栈上的数组时,我们会再添加一个操作数——堆栈指针。x86寻址模式提供了这样的地址-基数+小数位数*索引+偏移量。所以,好的堆栈数组元素访问:temp=mem[sp+基地址+迭代器*元素大小]和堆数组访问:temp=mem[基地址+迭代器*元素尺寸]。显然,堆栈访问的成本肯定比阵列访问的成本高。
现在,对于迭代的一般情况,如果堆栈的迭代速度较慢,则意味着寻址模式可能是瓶颈(我不完全确定),如果分配空间是瓶颈,则系统调用可能是瓶颈。
- 如何以优化的方式同时迭代两个间距不相等的数组
- 为什么我的 scanf() 没有在我的数组上迭代我的 for 循环?
- 迭代器库中的 std::size() 不适用于传递给函数的 C 样式数组
- 自定义 STL 兼容迭代器,用于迭代 2D 数组类的列
- 在C++中使用 for 循环的数组迭代
- 如何使用基于范围的for循环迭代Rapidjson文档(它本身就是一个JSON数组)
- 获取 c++ 中具有恒定长度的数组的迭代器
- 指针到指针 2-D 数组中的迭代
- 如何通过引用对用户定义对象的类型集 (STL) 的数组元素进行增强迭代?
- 迭代一组和擦除元素
- 为自定义数组实现迭代器
- C++,删除函数/迭代进程中定义的动态数组
- 迭代 txt 文件中的对象数组
- 原始数组和 std::array 在 clang++ 和 VC++ 上的不同迭代器行为
- 用std :: apply迭代元组元素
- C :优雅地迭代一组数字
- 在 C++17/20 中迭代元组
- 如何在表达式中迭代命名组
- Boost c++ -动态迭代多数组
- 如何在c++映射中迭代一组特定的键