我正在开发一个软实时事件处理系统。我希望尽量减少代码中具有不确定时间的调用数。我需要构造一个由字符串、数字、时间戳和GUID组成的消息,可能是std::vector of boost::variant's。
我一直希望在过去类似性质的代码中使用alloca。然而,当您查看系统编程文献时,总是会有大量的警告来防止这个函数调用。就我个人而言,在过去的15年里,我想不出一台没有虚拟内存的服务器类机器,而且我知道windows堆栈会在一段时间内生成一个虚拟内存页面,所以我认为Unices也是这样做的。这里已经没有砖墙了,堆叠就像堆一样有可能耗尽空间,那么是什么原因呢?为什么人们不去找阿罗卡呢?我可以想到很多用例--负责地使用alloca (字符串处理任何人?)。
无论如何,我决定测试性能差异(见下文),alloca和malloc之间有5倍的速度差异(测试捕获了我将如何使用alloca)。那么事情变了吗?当我们完全确定对象的生命周期时,我们是否应该谨慎行事,使用alloca (包装在std::allocator中)?
我厌倦了生活在恐惧中!
编辑:
好的,所以有限制,对于窗口来说,这是一个链接时间限制。对于Unix,它似乎是可调的。似乎有一个与页面对齐的内存分配器是合适的:是否有人知道通用的可移植实现: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完善工具的结果--
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发布于 2011-04-27 16:53:41
首先,尽管有大量的虚拟内存,但并不意味着您的进程将被允许填充它。在*nix上有堆栈大小限制,而堆则要宽容得多。
如果您只分配几十万字节,请继续。除此之外的任何事情都将取决于对任何给定系统的限制(ulimit),而这只是一个灾难的处方。
Why is the use of alloca() not considered good practice?
在“工作中的开发”框(Gentoo)上,我的默认堆栈大小限制为8192 kb。这不是很大,如果alloca溢出堆栈,那么行为就没有定义。
发布于 2011-04-27 17:22:12
我认为你在理解阿洛卡是什么的时候需要小心一点。与进入堆中的malloc不同,它通过桶和各种缓冲区的链接列表进行搜索,alloca只需要您的堆栈寄存器(x86上的ESP),并将它移动到在线程堆栈上创建一个“洞”,在那里您可以存储任何您想要的东西。这就是为什么它是快速的,只是一个(或少数)组装指令。
因此,正如其他人所指出的,您需要担心的不是“虚拟内存”,而是为堆栈保留的大小。尽管其他人将自己限制为“几百字节”,但只要您了解您的应用程序并小心处理,我们就分配了256 1mb,没有任何问题(默认的堆栈大小,至少对于visual studio,是1mb,如果需要的话,您可以随时增加它)。
而且,您确实不能使用alloca作为通用分配器(即将其封装在另一个函数中),因为无论为您分配什么内存分配,当当前函数的堆栈框架弹出时(即当函数退出时),该内存将消失。
我也见过一些人说过,alloca并不完全兼容跨平台,但是如果您正在为特定平台编写特定的应用程序,并且您可以选择使用alloca,那么有时这是最好的选择,只要您了解增加堆栈使用的含义。
发布于 2011-04-28 15:49:20
首先,这是因为alloca内存很难控制。它是未输入的,尽早死亡,这使得它没有多大帮助。此外,alloca还有一些不幸的副作用,这些副作用是,常规堆栈变量现在必须被动态索引,而不是常量,这可能会影响您在访问它们的基本操作中的性能,并消耗寄存器/堆栈空间来存储动态偏移量。这意味着使用alloca的实际成本并不是记录在函数返回所需的时间内。此外,与堆内存相比,堆栈内存非常有限--在Windows上,堆栈限制默认为8MB,而堆几乎可以是整个用户地址空间。更重要的是,最终您想返回的任何数据都必须在堆上,所以您可以像使用工作空间一样使用它。
https://stackoverflow.com/questions/5807612
复制相似问题