关于alloca的使用和滥用
|
我正在开发一个软实时事件处理系统。我想尽量减少代码中具有不确定时间的调用。我需要构造一条由字符串,数字,时间戳和GUID组成的消息。可能是
boost::variant
的std::vector
。
我一直想在过去类似性质的代码中使用alloca
。但是,当您查阅系统编程文献时,始终会对这种函数调用保持大量警惕。我个人认为在过去的15年中没有虚拟内存的服务器类计算机,而且我知道Windows堆栈一次可以增加虚拟内存页面这一事实,因此我认为Unices也是如此。这里(再也没有)没有砖墙,堆栈就像堆一样会耗尽空间,那又如何呢?人们为什么不反对阿洛卡?我可以想到负责使用alloca的许多用例(对任何人进行字符串处理?)。
无论如何,我决定测试性能差异(请参见下文),并且alloca和malloc之间的速度差异为5倍(该测试捕获了我将如何使用alloca)。那么,事情变了吗?只要我们可以绝对确定物体的寿命,我们是否应该对风吹牛并使用alloca
(包裹在std::allocator
中)?
我厌倦了恐惧!
编辑:
好的,所以有限制,对于Windows,这是一个链接时间限制。对于Unix,这似乎是可调的。似乎页面对齐的内存分配器是按顺序排列的:D任何人都知道通用的可移植实现:D吗?
码:
#include <stdlib.h>
#include <time.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using namespace boost::posix_time;
int random_string_size()
{
return ( (rand() % 1023) +1 );
}
int random_vector_size()
{
return ( (rand() % 31) +1);
}
void alloca_test()
{
int vec_sz = random_vector_size();
void ** vec = (void **) alloca(vec_sz * sizeof(void *));
for(int i = 0 ; i < vec_sz ; i++)
{
vec[i] = alloca(random_string_size());
}
}
void malloc_test()
{
int vec_sz = random_vector_size();
void ** vec = (void **) malloc(vec_sz * sizeof(void *));
for(int i = 0 ; i < vec_sz ; i++)
{
vec[i] = malloc(random_string_size());
}
for(int i = 0 ; i < vec_sz ; i++)
{
free(vec[i]);
}
free(vec);
}
int main()
{
srand( time(NULL) );
ptime now;
ptime after;
int test_repeat = 100;
int times = 100000;
time_duration alloc_total;
for(int ii=0; ii < test_repeat; ++ii)
{
now = microsec_clock::local_time();
for(int i =0 ; i < times ; ++i)
{
alloca_test();
}
after = microsec_clock::local_time();
alloc_total += after -now;
}
std::cout << \"alloca_time: \" << alloc_total/test_repeat << std::endl;
time_duration malloc_total;
for(int ii=0; ii < test_repeat; ++ii)
{
now = microsec_clock::local_time();
for(int i =0 ; i < times ; ++i)
{
malloc_test();
}
after = microsec_clock::local_time();
malloc_total += after-now;
}
std::cout << \"malloc_time: \" << malloc_total/test_repeat << std::endl;
}
输出:
hassan@hassan-desktop:~/test$ ./a.out
alloca_time: 00:00:00.056302
malloc_time: 00:00:00.260059
hassan@hassan-desktop:~/test$ ./a.out
alloca_time: 00:00:00.056229
malloc_time: 00:00:00.256374
hassan@hassan-desktop:~/test$ ./a.out
alloca_time: 00:00:00.056119
malloc_time: 00:00:00.265731
-编辑:在家用计算机,clang和Google perftools上的结果-
G++ without any optimization flags
alloca_time: 00:00:00.025785
malloc_time: 00:00:00.106345
G++ -O3
alloca_time: 00:00:00.021838
cmalloc_time: 00:00:00.111039
Clang no flags
alloca_time: 00:00:00.025503
malloc_time: 00:00:00.104551
Clang -O3 (alloca become magically faster)
alloca_time: 00:00:00.013028
malloc_time: 00:00:00.101729
g++ -O3 perftools
alloca_time: 00:00:00.021137
malloc_time: 00:00:00.043913
clang++ -O3 perftools (The sweet spot)
alloca_time: 00:00:00.013969
malloc_time: 00:00:00.044468
没有找到相关结果
已邀请:
5 个回复
窝头菊
黎喊病
誓猎贰
的实际成本不会仅仅在函数返回所花费的时间内记录下来。此外,与堆内存相比,栈内存非常有限-我相信在Windows上默认情况下,栈限制为8MB,而堆几乎可以是整个用户地址空间。不仅如此,最终,无论您要返回什么数据,都必须放在堆中,因此您最好将其用作工作空间。
期差骇蓟
,但具有结构化内存,而不是N字节的块-也许您可以认为这是对您的主要观点的敬意,这就是更多地使用基于堆栈的内存是一个好主意。我会比在C ++程序中使用
(或
)更早地做到这一点(将对象实例声明为RAII本地)。所有那些
调用都使异常安全... 这通常假定对象的范围仅限于此功能及其调用的功能。如果不是这种情况,那么使用基于堆栈的内存通常不是一个好主意。
臀夯脖锑
可以轻松超过该大小。