Использует ли malloc () brk () или mmap ()?

c код:

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

При компиляции следующего кода:

 printf("%10p\n", sbrk(0));

Я получаю предупреждающий совет:

format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’

Вопрос 1: Почему?


И после того, как я malloc(1024 * 1024), похоже, программный разрыв не изменился.

Вот результат:

9b12000
9b12000
9b12000

Вопрос 2: Выделяет ли процесс память в куче при запуске для использования в будущем? Или компилятор меняет момент времени на выделение? Иначе зачем?


[обновление] Сводка: brk () или mmap ()

Изучив TLPI и проверив справочную страницу (с помощью автора TLPI), теперь я понимаю, как malloc() решил использовать brk() или mmap(), а именно:

mallopt() может устанавливать параметры для управления поведением malloc(), и есть параметр с именем M_MMAP_THRESHOLD, в общем:

  • Если запрошенная память меньше, будет использовано brk();
  • Если запрошенная память больше или равна ей, будет использовано mmap();

Значение параметра по умолчанию - 128kb (в моей системе), но в моей тестовой программе я использовал 1 МБ, поэтому было выбрано mmap(), когда я изменил запрошенную память на 32 КБ, я увидел, что будет использоваться brk().

В книге это упоминается на страницах 147 и 1035 TLPI, но я не стал внимательно читать эту часть.

Подробную информацию о параметре можно найти на странице руководства для mallopt().


person user218867    schedule 30.05.2015    source источник
comment
@ JS1 Да, проблема решена, не могли бы вы объяснить, я новичок в программировании под Linux ...   -  person user218867    schedule 30.05.2015
comment
Вам нужен прототип для sbrk(), который находится в unistd.h. Без прототипа компилятор предполагает, что неизвестные функции возвращают int.   -  person JS1    schedule 30.05.2015
comment
@ JS1 Да, я думал, что sbrk() был объявлен в stdlib.h, спасибо!   -  person user218867    schedule 30.05.2015
comment
@ JS1 Мне интересно, не должно ли это выдавать ошибку компиляции, если я пропустил заголовок? Но этого не случилось ...   -  person user218867    schedule 30.05.2015
comment
@EricWang: Будет выдано предупреждение, если вы скомпилировали с -Wall (при условии, что вы используете gcc или clang). Вы всегда должны компилировать с -Wall.   -  person rici    schedule 30.05.2015
comment
@rici Да, я просто пытаюсь скомпилировать с -Wall и вижу предупреждение warning: implicit declaration of function ‘sbrk’, хороший совет!   -  person user218867    schedule 30.05.2015


Ответы (3)


Если мы изменим программу, чтобы увидеть, где находится память malloc'd:

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

Возможно, немного яснее, что sbrk не изменится. Память, предоставленная нам malloc, отображается в совершенно другом месте.

Вы также можете использовать strace в Linux, чтобы увидеть, какие системные вызовы выполняются, и узнать, что malloc использует mmap для выполнения распределения.

person Jay Kominek    schedule 30.05.2015
comment
Я обнаружил, что есть THRESHOLD, чтобы контролировать, использовать ли brk() или mmap(), я обновил это в вопросе. - person user218867; 03.06.2015

malloc не ограничивается использованием sbrk для выделения памяти. Например, он может использовать mmap для отображения большого MAP_ANONYMOUS блока памяти; обычно mmap назначает виртуальный адрес далеко от сегмента данных.

Есть и другие возможности. В частности, malloc, являясь основной частью стандартной библиотеки, сам по себе не ограничивается функциями стандартной библиотеки; он может использовать интерфейсы, специфичные для операционной системы.

person rici    schedule 30.05.2015
comment
Вы хотите сказать, что mmap может выделить больше памяти, чем sbrk? Если да, то где sbrk распределяет память и где mmap распределяет память? +1 - хороший ответ. - person xilpex; 29.05.2020
comment
sbrk выделяет память в определенном месте; каждый раз, когда вы вызываете sbrk, вы получаете кусок памяти, смежный с предыдущим вызовом. Исторически это была граница между кучей и стеком (при росте кучи от сегмента данных и от стека до конца адресного пространства процесса). mmap обычно не может выделить больше памяти, но определенно может выделить ее с другим адресом и с гораздо большим количеством параметров (флаги защиты памяти, резервное хранилище, огромные виртуальные блоки (для уменьшения размера таблицы страниц) и т. Д.) - person rici; 30.05.2020
comment
@petercordes: Да, почти уверен, что я действительно это имел в виду. Спасибо. - person rici; 24.09.2020

Если вы используете malloc в своем коде, он вызовет brk() в начале, выделив 0x21000 байт из кучи, это адрес, который вы напечатали, поэтому Вопрос 1: следующие требования mallocs могут быть выполнены из предварительно выделенного пространства, поэтому эти mallocs на самом деле не вызывает brk, это оптимизация в malloc. Если в следующий раз вы захотите изменить размер за пределы этой границы, будет вызван новый brk (если он не больше порогового значения mmap).

person elson2885150    schedule 31.01.2019