性能悖论:堆栈与堆分配(c++)
performance paradox: stack versus heap allocation (C++)
我昨天进行了一些性能测试,看看堆栈和堆分配将在实践中。从这样的测试中可以期望的是,堆分配稍微慢一些,或者与堆栈分配相当。然而,我惊讶地发现事实恰恰相反。我无法解释为什么,以及它在逻辑上是如何可能的,但是堆分配总是稍微快一些(我在编译时关闭了优化)。
这是一个示例输出:
ticks (stack): 42698
ticks (stack): 43977
ticks (stack): 44024
ticks (stack): 44070
ticks (stack): 45038
ticks (heap): 42588
ticks (heap): 43525
ticks (heap): 43633
ticks (heap): 43681
ticks (heap): 43071
这是一个很小的差异,但它是非常一致的,它复制了100%的时间,有利于堆分配。
谁能解释一下为什么我得到这些奇怪的结果?
这是我运行的代码:
#include <vector>
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
struct JJ
{
int c[50];
JJ(int i) { c[5] = 3; c[29] = 4; c[30] = i; c[49] = c[5]; }
};
void fill_direct_stack()
{
vector<JJ> vec;
for (int i=0; i<1000; ++i)
vec.push_back(i);
}
void fill_direct_heap()
{
vector<JJ>* pVec = new vector<JJ>();
for (int i=0; i<1000; ++i)
pVec->push_back(i);
delete pVec;
}
CRITICAL_SECTION cs_print;
void print(string msg, DWORD val)
{
EnterCriticalSection(&cs_print);
cout << msg << val << endl;
LeaveCriticalSection(&cs_print);
}
DWORD __stdcall threadEntry(void*)
{
DWORD ticks1,ticks2;
ticks1 = GetTickCount();
for (int i=0; i<10000; ++i)
fill_direct_stack();
ticks2 = GetTickCount();
print("ticks (stack): ", ticks2 - ticks1);
ticks1 = GetTickCount();
for (int i=0; i<10000; ++i)
fill_direct_heap();
ticks2 = GetTickCount();
print("ticks (heap): ", ticks2 - ticks1);
return 0;
}
int main()
{
cout<<"hi"<<endl;
InitializeCriticalSection(&cs_print);
#define N_THREADS 5
HANDLE thr[N_THREADS];
for (int i=0; i<N_THREADS; ++i)
thr[i] = CreateThread(NULL, 0, &threadEntry, NULL, 0, NULL);
for (int i=0; i<N_THREADS; ++i)
WaitForSingleObject(thr[i], INFINITE);
DeleteCriticalSection(&cs_print);
system("pause");
}
分配
vector<JJ>* pVec = new vector<JJ>();
和
vector<JJ> vec;
与vector
的回推和内部内存管理相比,没有。
很难说在这样一个人为的基准中是什么导致了如此微小的差异。但我猜这是一个结盟问题。如果从堆中进行分配,就会得到一块适合存储任何类型的内存。如果你从堆栈中分配内存,你得到的内存块只是最低限度地对齐,适合你存储的类型。
我的另一个理论是,这是数据缓存命中率。考虑一个线程完成,然后另一个线程在同一核心上运行。使用堆栈分配时,分配将永远不会分配到相同的内存块,因为每个线程都有自己的堆栈。数据缓存将是冷的。使用堆分配时,分配可能会获得前一个线程刚刚释放的相同块。内存块将在CPU数据缓存中处于热状态。(这个理论可以预测到相当多的数字变化——我认为比你看到的要多。)
但是差别很小,可以是任何东西
相关文章:
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 获取字符串的长度并将其分配给数组
- 将地址分配给本地指针后,公共对象的变量将消失
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 我在二维向量中是否正确分配了内存
- 正在尝试重载二进制搜索树分配运算符
- GlobalAlloc而不是其他分配方法
- 自定义先决条件对移动分配运算符有效吗
- 我可以重新分配/覆盖std::字符串吗
- 在c++中使用动态分配的问题
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- 为什么我可以使用比分配的内存更多的内存
- 使用RAII在给定次数的迭代后重新分配资源