开发者

What is the malloc behaviour if we can't free it

开发者 https://www.devze.com 2023-02-10 09:00 出处:网络
I have a question about malloc behavior. There is 2 c file myTools.c and mainFile.c mainFile.c is => int main(){

I have a question about malloc behavior. There is 2 c file

myTools.c and mainFile.c

mainFile.c is =>

int main(){
    int i=1;
    char *request="blablabla"//vary in situation.Not static
    while(i==1)//forever Loop
    {
      ...
      strcpy(response,getFile(request));
      ...
    }
}

myTools.c is ==>

.
.//something else
.
char *getFile(char *request)
{
  char *retVal;
  ...//some tcp request
  retVal=malloc(strlen(buffer));
  strcpy(retVal,buffer);
  ..//some char array operations
  return retVal;    
}
.
.//something else
.

I cant found a way to free the retVal or i wonder 开发者_开发技巧that i need to free the retVal ?

It works on uClinux on an m68k embedded platform so memory is limited.

May it couse any memory problem or any memory starvation?

Or effects the program's runtime behaviour?


You will leak memory every time getFile() is called.

One solution would be:

while(i==1)//forever Loop
{
  ...
  char* temp = getFile( request );

  strcpy(response,temp);

  free( temp );
  ...
}


Since you're returning a pointer from getFile(), perhaps you could simply assign it to the pointer variable in main(), bypassing the double use of strcpy()? Then you can free() the memory in main().

I'm not certain, but don't see why that would not work.


strcpy(response,getFile(request)) is likely to crash your program because response points to read-only memory.


strcpy(response,getFile(request)); 

Should be splited into:

char *tmp = getFile(request);
strcpy(response, tmp );
free( tmp );

This is sometimes refered as strdup() style allocation which is not recommended. You should allocate the buffer in the calling code like:

char *buf2 = malloc(strlen(buffer));   

and call

getFile( buf2, strlen( buffer ), input );
// use buf2
free( buf2 );


In embedded systems malloc() is often used to allocate memory on startup that will be used while the system is running and never free()d.

But you shouldn't do something like this periodically since it will use up your memory if you don't free() it again.

What you are doing in your example is leak one buffer worth of memory each round in the while loop.

What you should do is either, call free() in your loop but be aware this can still fragment menmory which is especially bad in an long running embedded system.

If you know in advance how much memory you will need in advance: malloc the buffer once outside the loop and reuse it in the loop:

response = malloc(MAX_BUF_SIZE);
while (1) {
    get_file(response, MAX_BUF_SIZE);    /* always good to pass the buf size and check */      ... use response ...
}

Or if you don't know the size in advance one pattern can be:

response = NULL;
size = 0;
while (1) {
    get_file(&response, &size);
    ... use response ...
}

void get_file(char **buf, int *s)
{
    size = ... somehow determine the needed size ...
    if (size > *s)
        *buf = realloc(*buf, size);     /* only does free/malloc internaly if it has to no room */
    strncpy(*buf, whatver, size);
 }

And you should always use strncpy and never strcpyplease!

The use of strcpy in your example is confusing, it can't be seen where response gets its memory, is it statically allocated? Has it been malloced before?

If response already points to a vaid buffer you should just pass the pointer to the buffer to your getFile() and directly copy the buffer there.

If response doesn't point to a valid memory buffer this will not work anyway.


Whenever you're creating an interface to some functionality you need to think about resource management - what's the lifetime of various objects and how the lifetime of those objects is managed. This is particularly true for languages like C and C++ which don't implement garbage collection, but even in garbage collected languages, some thought needs to be given to this (for non-memory resources and maybe to ensure that object references aren't held indefinitely).

Anyway, for C, APIs can deal with 'output' objects in several ways. Some of the more common patterns are:

  1. have the caller provide a buffer or object to place results in
  2. have the callee allocate a buffer or object, and return a pointer to the allocated object
  3. have the caller return the object directly from the function - this only works for items that have a fixed size (an intrinsic type or a struct) - it doesn't work for arbitrary strings. So I won't discuss this further.

For option 1, the caller provides a buffer to place results in by passing a pointer. For variable length data, like a string, it's important that the interface also allow the caller to pass in the size of the output buffer so the function can avoid writing outside of the buffer. For your getFile() function, the prototype might look like:

int getFile(char const* request, char* result, int result_size);

The caller passes in a pointer to place the results and the size of the passed in buffer. The function might return a negative number on failure (say a network failure) and the size of the result on success. If the size returned on success is larger than the buffer provided, then the caller knows that the full result wasn't placed in the buffer (since it's not large enough). If you go this route, it's important to take into consideration the '\0' terminator character and clearly indicate whether or not it's included in the return value and whether the buffer is terminated if the result is too large (which I recommend). Also, make sure that if a zero-sized buffer is passed in, the function doesn't write anything to the buffer whether or not a non-NULL pointer is passed in (it's a common pattern to have the function return the required size of the buffer in this case).

For option 2, the function will allocate an appropriate buffer and return a pointer to that to the caller. In this case, there needs to be a way for the caller to free the buffer when it's done with it to avoid a memory leak. One way is to document that the caller needs to call free() on the pointer returned by the function (implying that the function will allocate the pointer using malloc() or calloc()). Another is to have the interface for using the function also include a deallocation routine, maybe getFile_free() (I'd definitely rethink the naming of these functions if I were to go this route). This gives the implementation of this API the freedom to allocate the buffers it returns however it sees fit - it's not constrained to use malloc()/free() (though it could).

For an embedded system (especially small ones - maybe not Linux-based systems), I think that people might opt for option 1. That gives the user of the API the freedom to avoid dynamic memory allocation altogether, and it's common for embedded systems to not use dynamic memory. Also, a system using dynamic memory allocation can still use option 1's pattern - it just takes a bit more work, but that work can be wrapped in something that looks exactly like option 2 anyway, so you can have your cake and eat it too.


Yes it will cause memory starvation eventually, which will lead to the crashing of your program.

A simple rule that helps solve this kind of problem is to always remember to free memory in the same scope as where it has been allocated, if possible.

In your case, it is obviously impossible to free it after the call to return, therefore it makes sense to actually allocate it in the parent scope, ie. in the main function, passing the allocated pointer as a second argument to the getFile function, and directly write into it, assuming you make sure it is large enough to contain all characters.


Firstly, the *retVal is placed in the getFile function, thus the scope of *retVal is limited to that particular function and the memory space it uses will automatically be set to FREE once the function terminates/returns.

The scope of a varible decides its lifetime/usability, also once the lifetime is over and you don't free the block the data stays there, it can be accessed through pointer, however the memory block is kind of MARKED AS FREE and is overwritten afterwards without any troubles.

Secondly, Nick is very correct,you will waste memory every time getFile() is called, as it is in main function and has scope till the program runs.

Hope this helps, if it doesn't I'll be glad to help just let me know :)

0

精彩评论

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