开发者

How to avoid dynamically allocating memory to save time?

I have a function which is called many times in my project:

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

Now, in some rare cases, I am getting a segmentation fault when the value of bar is large. I need to increase the size of arr, whose size I can know from value of ba开发者_高级运维r.

The obvious solution seems to dynamically allocate memory for arr depending on size of bar. However, this function is called very frequently, and I think allocating memory each time can decrease performance.

What should be my strategy to tackle this?


Two suggestions:

  1. Allocate dynamically, but reuse the buffer. So foo will also get a buffer as a parameter from the calling function (if called from the same function in a loop, for example. I wouldn't pass the buffer all over the program if foo is called from 100 different places). This way, you only have to allocate once the buffer needs to be increased.
  2. Declare a large local array as you do now, but make sure it's large enough before using it. If not, dynamically allocate one on the heap. Assuming the local array is large enough for most cases, you'll only allocate on the heap on rare occasions.

Edit:

Regarding #2, @David Heffernan got heat for suggesting the same option, as it might be a complication of the code. I don't think the following is very complicated:

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);
}

I've used similar code in some frequently invoked callback where I couldn't reuse the buffer, and eliminating the malloc on most cases has definitely improved performance. Whether that's the best solution for the OP I really don't know.


If heap allocation performance is an issue then you can retain the stack allocated buffer for when bar<1024, but use a heap allocated buffer otherwise.

I would recommend profiling your app to see if using a heap allocation is actually discernibly slower than the constant sized array on the stack. Modern heaps peform very well. Don't optimise your code in a way that obfuscates it unless there is a significant benefit.


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

First you need to resolve run-time errors and then go for performance issues. With the information you given, there is no relation between bar and the sizeof the array arr. You are getting segmentation faults probably because you are trying to access locations not from 0 to 1023. If what you want is array of bar length, then malloc it and free it when you no longer need it.


You should stick with allocating memory, if there is a possibility for bar to be greater than 1024. Besides, it may not be such a good idea to allocate 1kb in the stack, specially if your function may be called recursively (which I guess it doesn't). Keep around the allocations from previous calls, or use a pool of allocated buffers, in order to avoid freeing and reallocating memory if a previous allocation is enough. Prepare to face trouble on concurrent calls to foo.


Allow the user to supply the buffer, so that, if this function is invoked in a loop, the user can construct the buffer once (before the loop) and pass the same buffer in on each iteration. I.e., use:

 // 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);


I would do the following.

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

Declaring arr as array in the prototype is only cosmetics but clearly shows your intentions. (Another possibility would be to have char arr[static 1] to force it to be a non-null pointer.)

Then I would write a macro for the use case where the caller doesn't have an array at hand

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

or

#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

depending if you think VLA are safe for you or not in your situation.

On the call site you then can choose to call foo in places where you are sure it will not hurt too much, and optimize calls inside loops or so by allocating a buffer beforehand.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜