c-如何避免动态分配内存以节省时间



我有一个函数在我的项目中被调用了很多次:

void foo(int bar)
{  
    char arr[1024];
    //...do some operation on arr according to value of bar  
}

现在,在一些罕见的情况下,当bar的值较大时,我会遇到分割错误。我需要增加arr的大小,我可以从bar的值中知道它的大小。

显而易见的解决方案似乎是根据bar的大小为arr动态分配内存。然而,这个函数调用频率很高,我认为每次分配内存都会降低性能。

我应该采取什么策略来解决这个问题?

两个建议:

  1. 动态分配,但重用缓冲区。所以foo也会从调用函数中获得一个缓冲区作为参数(例如,如果在循环中从同一个函数调用。如果从100个不同的地方调用foo,我不会在整个程序中传递缓冲区(。这样,您只需要在需要增加缓冲区时进行分配
  2. 像现在一样声明一个大的本地数组,但在使用之前要确保它足够大。如果不是,请在堆上动态分配一个。假设本地数组在大多数情况下都足够大,那么您只会在极少数情况下在堆上进行分配

编辑:

关于#2,@David Heffernan因提出相同的选项而受到指责,因为这可能是代码的复杂性。我不认为以下内容很复杂:

void foo(int bar)
{
    char localArr[1024];
    char* arr = localArr;
    if (sizeNeeded > 1024)
        arr = malloc(sizeNeeded);
    // ... use arr in logic ...
    if (arr != localArr)
        free(arr);
}

我在一些频繁调用的回调中使用了类似的代码,在这些回调中我无法重用缓冲区,在大多数情况下消除malloc无疑提高了性能。我真的不知道这是否是OP的最佳解决方案。

如果堆分配性能是个问题,那么您可以在bar<1024,但在其他情况下使用堆分配的缓冲区。

我建议分析你的应用程序,看看使用堆分配是否真的比堆栈上的常量大小数组慢。现代的土堆堆得很好。除非有显著的好处,否则不要以混淆代码的方式优化代码。

void foo(int bar) {
    char arr[1024];
    // ...
}

首先,您需要解决运行时错误,然后再处理性能问题。根据您提供的信息,bar和数组arr的大小之间没有关系。您遇到分段错误,可能是因为您试图访问的位置不是从0到1023。如果你想要的是bar长度的数组,那么malloc是它,free是它,当你不再需要它时。

如果bar可能大于1024,则应坚持分配内存。此外,在堆栈中分配1kb可能不是一个好主意,特别是如果你的函数可能被递归调用(我想它不是(。保留以前调用的分配,或者使用已分配缓冲区池,以避免在以前的分配足够的情况下释放和重新分配内存。准备在并发调用foo时遇到麻烦。

允许用户提供缓冲区,这样,如果在循环中调用此函数,则用户可以构造一次缓冲区(在循环之前(,并在每次迭代中传递相同的缓冲区。即,用途:

 // Preconditions:
 //     buffer_ptr MUST NOT be NULL.
 //     buffer_len_ptr MUST NOT be NULL.
 //
 // Parameters:
 //     bar -- Whatever bar does
 //     buffer_ptr -- Points to a pointer to a malloc-allocated buffer.
 //     buffer_len_ptr -- Points to a variable indicating the size of *buffer_ptr
 //
 // Side-Effects:
 //     May expand the buffer, causing *buffer_ptr to point to a new, larger
 //     buffer, in which case *buffer_len_ptr will have the new size. 
 //
 void foo(int bar, char** buffer_ptr, size_t* buffer_len_ptr);

我将执行以下操作。

void foo_inner(size_t bar, char arr[bar]);

在原型中声明arr为数组只是化妆品,但它清楚地表明了您的意图。(另一种可能性是让char arr[static 1]强制它成为非空指针。(

然后,我会为调用方手头没有数组的用例编写一个宏

#define foo(BAR)              
if (1) {                      
  size_t foo_bar = BAR;       
  char foo_arr[foo_bar];      
  foo_inner(foo_bar, foo_arr);
} else (void)0

#define foo(BAR)                          
if (1) {                                  
  size_t foo_bar = BAR;                   
  char * foo_arr = malloc(foo_bar);       
  if(foo_arr) foo_inner(foo_bar, foo_arr);
  free(foo_arr);                          
} else (void)0

这取决于你是否认为VLA对你来说是安全的。

然后,在调用站点上,您可以选择在您确信不会造成太大伤害的地方调用foo,并通过预先分配缓冲区来优化循环内的调用。

相关内容

  • 没有找到相关文章

最新更新