昨天我正在进行一些性能测试,看看堆栈和放大器之间的差异有多大。堆分配将在实践中。 人们对这种测试的期望是堆分配略慢或与堆栈分配相同。 然而,我惊讶地发现了相反的情况。我无法解释为什么,以及它在逻辑上是如何可能的,但堆分配总是稍微快一点(我正在编译优化OFF)。
这是一个示例输出:
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");
}
答案 0 :(得分:6)
分配
vector<JJ>* pVec = new vector<JJ>();
和
vector<JJ> vec;
与vector
所做的回退和内部内存管理相比。
答案 1 :(得分:1)
很难说这种人为基准的差异是什么原因。但我的猜测是这是一个对齐问题。如果从堆中分配,则会得到一块适合存储任何类型的内存块。如果从堆栈中分配,则会得到一块内存,只有最小的对齐,适合您存储的类型。
我的另一个理论是它是数据缓存命中率。考虑一个线程完成,然后在同一个核心上运行另一个线程。使用堆栈分配,分配永远不会是同一块内存,因为每个线程都有自己的堆栈。数据缓存会很冷。使用堆分配,分配可能会获得前一个线程释放的相同块。 CPU数据缓存中的内存块将很热。 (这个理论可以预测数字中的相当多的变化 - 我认为比你看到的更多。)
但差异很小,可能是任何东西。