首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >论alloca的使用与滥用

论alloca的使用与滥用
EN

Stack Overflow用户
提问于 2011-04-27 16:45:49
回答 5查看 14.9K关注 0票数 24

我正在开发一个软实时事件处理系统。我希望尽量减少代码中具有不确定时间的调用数。我需要构造一个由字符串、数字、时间戳和GUID组成的消息,可能是std::vector of boost::variant's。

我一直希望在过去类似性质的代码中使用alloca。然而,当您查看系统编程文献时,总是会有大量的警告来防止这个函数调用。就我个人而言,在过去的15年里,我想不出一台没有虚拟内存的服务器类机器,而且我知道windows堆栈会在一段时间内生成一个虚拟内存页面,所以我认为Unices也是这样做的。这里已经没有砖墙了,堆叠就像堆一样有可能耗尽空间,那么是什么原因呢?为什么人们不去找阿罗卡呢?我可以想到很多用例--负责地使用alloca (字符串处理任何人?)。

无论如何,我决定测试性能差异(见下文),alloca和malloc之间有5倍的速度差异(测试捕获了我将如何使用alloca)。那么事情变了吗?当我们完全确定对象的生命周期时,我们是否应该谨慎行事,使用alloca (包装在std::allocator中)?

我厌倦了生活在恐惧中!

编辑:

好的,所以有限制,对于窗口来说,这是一个链接时间限制。对于Unix,它似乎是可调的。似乎有一个与页面对齐的内存分配器是合适的:是否有人知道通用的可移植实现:D?

代码:

代码语言:javascript
复制
#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;
}

输出:

代码语言:javascript
复制
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完善工具的结果--

代码语言:javascript
复制
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
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-04-27 16:53:41

首先,尽管有大量的虚拟内存,但并不意味着您的进程将被允许填充它。在*nix上有堆栈大小限制,而堆则要宽容得多。

如果您只分配几十万字节,请继续。除此之外的任何事情都将取决于对任何给定系统的限制(ulimit),而这只是一个灾难的处方。

Why is the use of alloca() not considered good practice?

在“工作中的开发”框(Gentoo)上,我的默认堆栈大小限制为8192 kb。这不是很大,如果alloca溢出堆栈,那么行为就没有定义。

票数 18
EN

Stack Overflow用户

发布于 2011-04-27 17:22:12

我认为你在理解阿洛卡是什么的时候需要小心一点。与进入堆中的malloc不同,它通过桶和各种缓冲区的链接列表进行搜索,alloca只需要您的堆栈寄存器(x86上的ESP),并将它移动到在线程堆栈上创建一个“洞”,在那里您可以存储任何您想要的东西。这就是为什么它是快速的,只是一个(或少数)组装指令。

因此,正如其他人所指出的,您需要担心的不是“虚拟内存”,而是为堆栈保留的大小。尽管其他人将自己限制为“几百字节”,但只要您了解您的应用程序并小心处理,我们就分配了256 1mb,没有任何问题(默认的堆栈大小,至少对于visual studio,是1mb,如果需要的话,您可以随时增加它)。

而且,您确实不能使用alloca作为通用分配器(即将其封装在另一个函数中),因为无论为您分配什么内存分配,当当前函数的堆栈框架弹出时(即当函数退出时),该内存将消失。

我也见过一些人说过,alloca并不完全兼容跨平台,但是如果您正在为特定平台编写特定的应用程序,并且您可以选择使用alloca,那么有时这是最好的选择,只要您了解增加堆栈使用的含义。

票数 6
EN

Stack Overflow用户

发布于 2011-04-28 15:49:20

首先,这是因为alloca内存很难控制。它是未输入的,尽早死亡,这使得它没有多大帮助。此外,alloca还有一些不幸的副作用,这些副作用是,常规堆栈变量现在必须被动态索引,而不是常量,这可能会影响您在访问它们的基本操作中的性能,并消耗寄存器/堆栈空间来存储动态偏移量。这意味着使用alloca的实际成本并不是记录在函数返回所需的时间内。此外,与堆内存相比,堆栈内存非常有限--在Windows上,堆栈限制默认为8MB,而堆几乎可以是整个用户地址空间。更重要的是,最终您想返回的任何数据都必须在堆上,所以您可以像使用工作空间一样使用它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5807612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档