c code:
// program break mechanism
// TLPI exercise 7-1
#include <stdio.h>
#include <stdlib.h>
void program_break_test() {
printf("%10p\n", sbrk(0));
char *bl = malloc(1024 * 1024);
printf("%x\n", sbrk(0));
free(bl);
printf("%x\n", sbrk(0));
}
int main(int argc, char **argv) {
program_break_test();
return 0;
}
When compiling following code:
printf("%10p\n", sbrk(0));
I get warning tip:
format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’
Question 1: Why is that?
And after I malloc(1024 * 1024)
, it seems the program break didn't change.
Here is the output:
9b12000
9b12000
9b12000
Question 2: Does the process allocate memory on heap when start for future use? Or the compiler change the time point to allocate? Otherwise, why?
[update] Summary: brk() or mmap()
After reviewing TLPI and check man page (with help from author of TLPI), now I understand how malloc()
decide to use brk()
or mmap()
, as following:
mallopt()
could set parameters to control behavior of malloc()
, and there is a parameter named M_MMAP_THRESHOLD
, in general:
- If requested memory is less than it,
brk()
will be used; - If requested memory is larger than or equals to it,
mmap()
will be used;
The default value of the parameter is 128kb
(on my system), but in my testing program I used 1Mb, so mmap()
was chosen, when I changed requested memory to 32kb, I saw brk()
would be used.
The book mentioned that in TLPI page 147 and 1035, but I didn't read carefully of that part.
Detailed info of the parameter could be found in man page for mallopt()
.
If we change the program to see where the malloc
'd memory is:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void program_break_test() {
printf("%10p\n", sbrk(0));
char *bl = malloc(1024 * 1024);
printf("%10p\n", sbrk(0));
printf("malloc'd at: %10p\n", bl);
free(bl);
printf("%10p\n", sbrk(0));
}
int main(int argc, char **argv) {
program_break_test();
return 0;
}
It's perhaps a bit clearer that sbrk
wouldn't change. The memory given to us by malloc
is being mapped into a wildly different location.
You could also use strace
on Linux to see what system calls are made, and find out that malloc
is using mmap
to perform the allocation.
malloc
is not limited to using sbrk
to allocate memory. It might, for example, use mmap
to map a large MAP_ANONYMOUS
block of memory; normally mmap
will assign a virtual address well away from the data segment.
There are other possibilities, too. In particular, mmap
, being a core part of the standard library, is not itself limited to standard library functions; it can make use of operating-system-specific interfaces.
format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’
Answer to question 1: The compiler is telling you the argument should be a void *
, but you're providing an int
instead. That ought to be obvious if you spend five seconds reading and understanding the error. Is there any part of that you don't understand? If so, ask a more detailed question about that which confuses you, rather than "Why is that?"...
A similar warning should occur for printf("%x\n", sbrk(0));
, as according to the manual, %x
is expected to correspond to an unsigned
parameter. Also, according to the manual:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Normally, we should strive to write programs that work the same way on any system. In order to do that we need to have a set of rules established. Hence, a warning is provided to tell you that you're breaking the rules and invoking undefined behaviour. In spite of your undefined behaviour, your code may work as you expect it to on your system, at this point in time... However, this shouldn't be relied upon because at some point in the future your computer might fetch an update that causes your code to break in subtle yet devastating ways, or might fail to work on other computers... or might just choose to have that time of the month.
Answers to questions 2, 3 and 4:
Does the process allocate memory on heap when start for future use?
There is no requirement that a 'heap' exist within the rules of standard C, so that's a "no"... At least, not until you tell us which compiler/standard library you're using.
Or the compiler change the time point to allocate?
Possibly. Compilers are allowed to perform optimisations that might even eliminate your allocation, providing they can deduce that it's safe to do so (e.g. the observable behaviour isn't changed).
Otherwise, why?
Good question.
Why do we have rules that are free to consider something undefined behaviour and allow it to run, even at the peril of the programmer? Optimisation.
Why does it matter whether the memory you allocate goes on the heap or otherwise? Why should you care? So long as your memory is allocated, right? So long as you can use it, and it's reasonably fast. Optimisation.
Why does the compiler perform optimisation? I'll leave that one for you to answer ;)
If you use malloc in your code, it will call brk() at the beginning, allocated 0x21000 bytes from the heap, that's the address you printed, so the Question 1: the following mallocs requirements can be meet from the pre-allocated space, so these mallocs actually did't call brk, it is a optimization in malloc. If next time you want to malloc size beyond that boundary, a new brk will be called (if not large than the mmap threshold).
来源:https://stackoverflow.com/questions/30542428/does-malloc-use-brk-or-mmap