tags:

views:

182

answers:

10

I have read that free() "generally" does not return memory to the OS. Can we portably make use of this feature of free(). For example,is this portable?

 /* Assume I know i would need memory equivalent to 10000 integers at max
    during the lifetime of the process */

 unsigned int* p = malloc(sizeof(unsigned int) * 10000);

 if ( p == NULL)
  return 1;

 free(p);

 /* Different points in the program */

 unsigned int* q = malloc(sizeof(unsigned int) * 5);

 /* No need to check for the return value of malloc */

I am writing a demo where I would know in advance how many call contexts to support.

Is it feasible to allocate "n" number of "call contexts" structures in advance and then free them immediately. Would that guarantee that my future malloc calls would not fail?

Does this give me any advantage with regards to efficiency? I am thinking one less "if" check plus would memory management work better if a large chunk was initially acquired and is now available with free. Would this cause less fragmentation?

+4  A: 
  1. No, you can't reliably do such a thing. It is portable only in the sense that it's valid C and will probably compile anywhere you try it, but it is still incorrect to rely on this supposed (and undocumented) behaviour.

  2. You will also not get any appreciably better performance. A simple check for NULL returns from malloc() is not what's making your program slow. If you think all your calls to malloc() and free() are slowing your program down, write your own allocation system with the behaviour you want.

Carl Norum
@Carl, doesn't it really depend on if there was a context switch in between "free" and the last "malloc" ? + number of hungry processes at that time.
Gollum
@Gollum, I guess that depends on your system. `malloc()` can be implemented in lots of ways.
Carl Norum
if its implemented this way, how does the current process know when to release the memory? cos it will stall all other processes if the current process gets a large chunk and frees it immediately and does that often. I am not expert or pro; a student trying to understand (not arguing)
Gollum
@Gollum. On *NIX malloc() would extend data segment (`man brk`) and memory normally isn't returned to the OS. Presumption is that if you needed the memory once, then you might need it later too. If you need huge chunk of memory for a relatively short time, then you can use e.g. `mmap( 0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 )` to allocate the chunk and `munmap()` to free it.
Dummy00001
+7  A: 

You would be better off keeping the initial block of memory allocated then using a pool to make it available to clients in your application. It isn't good form to rely on esoteric behaviors to maintain the stability of your code. If anything changes, you could be dealing with bad pointers and having program crashes.

Amardeep
...which is almost as simple as omitting the `free(p)` at the start, then doing `unsigned int *q = p; p += 5;` at the allocation step.
caf
+4  A: 

You cannot portably rely on any such behavior of malloc(). You can only rely on malloc() giving you a pointer to a block memory of the given size which you can use until you call free().

JesperE
No, you can only rely in malloc giving you a pointer and *hope* it isn't **NULL**.
jbcreix
:-) Yes, of course.
JesperE
+3  A: 

No, there's no guarantee free() will not release the memory back, and there's no guarantee your second malloc will succeed.

Even platforms who "generally" don't return memory to the OS, does so at times if it can. You could end up with your first malloc succeeding, and your next malloc not succeding since in the mean time some other part of the system used up your memory.

nos
context switch after the free, and the process a little hungry, is all it takes to fell this tree(code) !( ps. programmers can be creative ;) )
Gollum
+3  A: 

Not at all. It's not portable at all. In addition, there's no guarantee that another process won't have used the memory in question- C runs on many devices like embedded where virtual memory addressing doesn't exist. Nor will it reduce fragmentation- you'd have to know the page size of the machine and allocate an exact number of pages- and then, when you freed them, they'd be just unfragmented again.

If you really want to guarantee malloced memory, malloc a large block and manually place objects into it. That's the only way. As for efficiency, you must be running on an incredibly starved device in order to save a few ifs.

DeadMG
+1  A: 

The C standard can be read as requiring this, but from a practical viewpoint there are implementations known that don't follow that, so whether it's required or not you can't really depend on it.

So, if you want this to be guaranteed, you'll pretty much need to write your own allocator. A typical strategy is to allocate a big block from malloc (or whatever) and sub-allocate pieces for the rest of the program to use out of that large block (or perhaps a number of large blocks).

Jerry Coffin
+4  A: 

Hmm, no. What malloc(3) does internally is call the brk(2) to extend the data segment if it's too small for given allocation request. It does touch some of the pages for its internal bookkeeping, but generally not all allocated pages might be backed by physical memory at that point.

This is because many OS-es do memory overcommit - promising the application whatever it requested regardless of available physical memory in hopes that not all memory will be used by the app, that other apps release memory/terminate, and falling back on swapping as last resort. Say on Linux malloc(3) pretty much never fails.

When memory actually gets referenced the kernel will have to find available physical pages to back it up, create/update page tables and TLBs, etc. - normal handling for a page fault. So again, no, you will not get any speedup later unless you go and touch every page in that allocated chunk.

Disclamer: the above is might not be accurate for Windows (so, no again - nothing close to portable.)

Nikolai N Fetissov
nice and precise explanation, but what happens when you try to access after its been freed ? the process keeps the memory for sometime, how long is that? and what does it depend on?
Gollum
@Gollum: You don't know and you don't care. You're not allowed to try to peak, and doing so just because you can get away with it on FooOS v2.1718 is wrong.
dmckee
It's give-or-take accurate for Windows- it's done virtual memory for a long time. I don't know about overcommitting the memory, though Windows does make good use of page file.
DeadMG
+5  A: 

You are asking for a portable and low level way to control what happens on the OS side of the memory interface.

On any OS (because c is one of the most widely ported languages out there).

Think about that and keep in mind that OSs differ in their construction and goals and have widely varying sets of needs and properties.

There is a reason the usual c APIs only define how things should look and behave from the c side of the interface, and not how things should be on the OS side.

dmckee
+3  A: 

malloc(3) also does mmap(2), consequently, free(3) does munmap(2), consequently, second malloc() can in theory fail.

adobriyan
A: 

For better control you should create your own memory allocator. An example of memory allocator is this one. This is the only way you will have predictable results. Everything else that relies on obscure/undocumented features and works can be attributed to luck.

Iulian Şerbănoiu