gcc 哪种分配速度更快?malloc vs局部变量

iqxoj9l9  于 2023-06-23  发布在  其他
关注(0)|答案(8)|浏览(170)

对于一个频繁分配和释放内存的函数,哪种分配内存的方法更可取?假设此函数在1GHz处理器上每秒调用约500到1000次。
(请忽略静态和全局变量/分配。我只对这个具体案例感兴趣:)

void Test()
{
    ptr=malloc(512)   // 512 bytes
    ...
    free(ptr) 
}

void Test()
{
     struct MyStruct localvar; // 512 byte sized structure
     ... 
}
vof42yt1

vof42yt11#

局部变量的堆栈分配比malloc的堆分配快。然而,总堆叠空间是有限的(例如,到几兆字节)。因此,您应该将自己限制为本地堆栈上的“小”数据。(512字节按照今天的标准是小的,但是256Kb对于本地堆栈分配来说太大了)。
如果你的函数是非常递归的,那么即使是512字节也可能太大了,因为每个递归调用帧都需要这个字节。
但是每秒调用几千次malloc应该是无痛的(恕我直言,典型的小型malloc需要几十微秒)。
出于好奇心,在C世界之外,您可能会对老A.阿 perl 的论文garbage collection can be faster than stack allocation感兴趣(但今天可能缓存性能方面的考虑会削弱这种说法)。

yruzcnhs

yruzcnhs2#

局部变量基本上是“免费”分配的,所以如果我们只对性能感兴趣,这里就没有竞争了。
不过:

  • 在局部变量和堆分配变量之间进行选择通常不是你可以不受约束地自由决定的;通常情况下,有一些因素决定了你的选择,所以你的问题有点可疑,因为它似乎忽略了这个问题
  • 虽然在堆栈上分配是“自由”的性能,但堆栈上的 * 空间 * 可能是有限的(尽管512字节当然不算什么)
tvokkenx

tvokkenx3#

  • 哪种方式是分配内存的最佳方式?
  • 哪种分配方式更快?

你想要更快的方式,还是更好的方式?
无论如何,在你提到的情况下,我认为第二种选择:

struct MyStruct localvar;

更有效,因为内存分配由 Stack 完成。这比使用malloc这样的动态内存分配函数要高效得多。

优化

此外,如果您这样做是为了性能和优化…
在我的PC上,使用malloc来分配字符串,而不是从堆栈中声明一个char数组,这给了我每个字符串大约73纳秒的延迟。
如果你在程序中复制了50个字符串:4757142 / 50 = 95142次(和一点)运行你的程序
如果我每天运行你的程序50次:95142 / 50 = 1902天(还有一点)
1902天= 5 1/5年
因此,如果你每天运行你的程序5年零2个月,你将保存额外眨眼的时间。哇,多么值得。。

4dbbbstv

4dbbbstv4#

当你输入你的函数时,打开反汇编器,并逐步完成这两种情况。
局部变量(基于堆栈)将需要0个额外的周期-您甚至看不到分配来自哪里,因为该函数将通过移动堆栈指针在1个周期内分配所有局部变量,并通过恢复堆栈指针在1个周期内释放所有局部变量。不管你有1个还是1000个局部变量,“分配”都需要相同的时间。
malloc变量...好吧,你很快就会厌倦点击步进通过成千上万的指令执行,以获得内存从系统堆。最重要的是,您可能会注意到,周期的数量因调用而异,这取决于您已经从堆中分配了多少东西,因为每次请求内存时,malloc都需要在堆结构中进行“搜索”。

我的经验法则:如果可能的话,总是使用堆栈,而不是malloc/freenew/delete。除了更快的性能外,您还可以获得不必担心内存或资源泄漏的额外好处。在C中,这只是意味着忘记调用free(),但在C++中,如果在调用delete之前抛出异常,异常可能会毁了你的一天。如果你使用堆栈变量,这一切都是自动处理的!但是,只有当您谈论的是“小”内存(字节和KB)而不是大对象(不是MB或GB!)。如果你谈论的是巨大的对象,那么你就不再谈论性能了,而且你可能不会在同一个函数调用中调用free/delete

btxsgosb

btxsgosb5#

堆栈分配比malloc + free快。
堆栈分配通常以指令为单位来衡量,而malloc + free可能需要多个锁(作为比较为什么需要很长时间的一个例子)。

gk7wooem

gk7wooem6#

局部变量的情况会更快:在堆栈上分配一个变量并不需要额外的时间,它只是改变了堆栈指针的移动量。而malloc将不得不做一些簿记。

gijlo24d

gijlo24d7#

使用堆栈的另一个优点是它不会将内存空间分割成碎片,而malloc往往会这样做。当然,这只是长时间运行的流程的问题。

pieyvz9o

pieyvz9o8#

/*  This question is still valid in 2023.  Like another poster, I 
discovered allocation, verifying allocation and freeing memory 
took very little processing time. */

/*  The SURPRISE was that memory ACCESS time was VASTLY 
different -- stack vs the heap! */

/*  Test Results for accessing a 500,000-byte block of memory:
    use_malloc()    elapsed_time_ms(3062)   iterations(10000)
    use_stack()     elapsed_time_ms(0)      iterations(10000)
*/

/*  - Using stack-based memory took virtually no time, but heap 
memory used 3 seconds. */

/*  I have a theory that maybe all that far-pointer arithmetic 
for accessing the heap is to blame -- the stack is nearer and 
maybe accessed with smaller (32bit?) integers?  Just a guess.*/

/*  MS says the default reserved stack space is 1MB today, if I 
understood.  (Encourage you to verify this on your own and for 
Your OS) */

/*  Hence, for my money, if I have to do some iteration-
intensive work on blocks of relatively small memory, for sure 
I'll be using the stack. */

/* Your mileage may vary; I respect your choice.  */
/* Code below... cheers! */

/*Here is the processing performed on the memory -- where 
len = 500000: */

void fill_buff(char *buff, int len)
{
    int iii;

    for(iii = 0; iii < len; iii++)
        buff[iii] = (char)(iii + 'A');
}

#define SIZE 500000

/*The two buffer-usage functions */

void use_stack(void)
{
    char buff[SIZE+1];

    fill_buff(buff, SIZE);
}

char *buff = NULL;

void use_malloc(void )
{
    fill_buff(buff, SIZE);
}

/* Test like so .... */
void run_test(long iterations)
{
    long iii;
    clock_t startt, endt, elapsed_time_ms;

    startt = clock();
    for(iii=0; iii < iterations; iii++)
    {
        use_malloc();
    }
    endt = clock();
    elapsed_time_ms = endt-startt;
    printf("use_malloc()  elapsed_time_ms(%d) iterations(%d)\n",
    elapsed_time_ms, iterations);
    
    //...
    //...
    //...
    use_stack();
    //...
    //...

}
main()
{
    buff = malloc(SIZE+1);

    if(buff)
        run_test(10*1000);
    //...
}

相关问题