33

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().

jww
  • 97,681
  • 90
  • 411
  • 885
Eric
  • 22,183
  • 20
  • 145
  • 196
  • 3
    `#include `? – JS1 May 30 '15 at 05:03
  • @JS1 Yes, that solved the issue, can you give an explaination, I am new to linux programming... – Eric May 30 '15 at 05:05
  • 2
    You need the prototype for `sbrk()` which is in `unistd.h`. Without a prototype, the compiler assumes that unknown functions return `int`. – JS1 May 30 '15 at 05:06
  • @JS1 Yeah, I thought `sbrk()` was declared in `stdlib.h`, thank you! – Eric May 30 '15 at 05:08
  • @JS1 I am wondering, shouldn't it give compile error, since I missed the header? But it didn't ... – Eric May 30 '15 at 05:17
  • 1
    @EricWang: It would give a warning if you compiled with -Wall (assuming you're using gcc or clang). You should always compile with -Wall. – rici May 30 '15 at 05:24
  • @rici Yes, I just try to compile with `-Wall`, and I see the warning `warning: implicit declaration of function ‘sbrk’`, nice tip! – Eric May 30 '15 at 05:26

3 Answers3

18

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.

Jay Kominek
  • 8,674
  • 1
  • 34
  • 51
  • 1
    I found that there is a `THRESHOLD` to control whether use `brk()` or `mmap()`, I updated that in the question. – Eric Jun 03 '15 at 16:58
7

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, malloc, 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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
rici
  • 234,347
  • 28
  • 237
  • 341
  • Are you saying that `mmap` can allocate more memory than `sbrk`? If so where does `sbrk` allocate memory, and where does `mmap` allocate memory? +1 -- good answer. – xilpex May 29 '20 at 20:09
  • 2
    sbrk allocates memory at a specific location; each time you call `sbrk` you get the a chunk of memory contiguous with the previous call. Historically, this was the frontier between the heap and the stack (with the heap growing up from the data segment and the stack growing down from the end of the process's address space). `mmap` cannot normally allocate more memory, but it definitely can allocate it with a different address and with a lot more options (memory protection flags, backing store, huge virtual blocks (to reduce page table size), etc.) – rici May 30 '20 at 00:04
  • @petercordes: Yep, pretty sure I did mean that. Thanks. – rici Sep 24 '20 at 04:11
6

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 didn'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).

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
elson2885150
  • 86
  • 1
  • 3