Как работает sbrk() в C++?

Где я могу прочитать о sbrk() в некоторых деталях?

Как это работает?

В каких ситуациях я хотел бы использовать sbrk() вместо громоздких malloc() а также new()?

Кстати, что расширение для sbrk()?

5 ответов

Решение

Посмотрите спецификацию для brk / sbrk.

Вызов в основном просит ОС выделить больше памяти для приложения, увеличив предыдущее "значение разрыва" на определенную величину. Это количество (первый параметр) - это количество дополнительной памяти, которое затем получает ваше приложение.

Большинство элементарных реализаций malloc основаны на системном вызове sbrk для получения блоков памяти, которые они разделяют и отслеживают. Функция mmap обычно считается лучшим выбором (именно поэтому mallocs, такие как dlmalloc, поддерживают оба с #ifdef).

Что касается "как это работает", то sbrk на самом простом уровне может выглядеть примерно так:

uintptr_t current_break; // Some global variable for your application.
                         // This would probably be properly tracked by the OS for the process
void *sbrk(intptr_t incr)
{
    uintptr_t old_break = current_break;
    current_break += incr;
    return (void*) old_break;
}

Современные операционные системы делают гораздо больше, например, страницы карты в адресном пространстве и добавляют информацию отслеживания для каждого выделенного блока памяти.

sbrk в значительной степени устарел, в наши дни вы используете mmap для отображения некоторых страниц в /dev/zero. Это, конечно, не то, что вы используете вместо malloc и друзей, это скорее способ их реализовать. Также, конечно, он существует только в операционных системах на основе posix, которые заботятся о обратной совместимости с древним кодом.

Если вы обнаружите, что Malloc и New слишком громоздки, вам следует вместо этого заняться сборкой мусора... но будьте осторожны, это может привести к снижению производительности, поэтому вам нужно понимать, что вы делаете.

Вы пометили этот C++, так почему бы вам использовать "громоздкий" malloc(), а не новый? Я не уверен, что громоздко в malloc в любом случае; внутренне может быть и так, но зачем тебе это? И если вам все равно (например, по причинам детерминизма), вы можете выделить большой пул и реализовать свой собственный распределитель для этого пула. Конечно, в C++ вы можете перегрузить оператор new, чтобы сделать это.

sbrk используется для приклеивания библиотеки C к управлению памятью операционной системы. Поэтому делайте вызовы ОС, а не используйте sbrk(). Что касается того, как это работает, это зависит от системы. Если, например, вы используете библиотеку Newlib C (обычно используемую в "голых железных " встраиваемых системах с компилятором GNU), вы должны внедрить sbrk самостоятельно, поэтому, как она работает в таких условиях, зависит от вас, пока она достигает его обязательное поведение расширения кучи или сбоя.

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

Вы никогда не хотите использовать sbrk вместо malloc или же free, Он непереносим и обычно используется только разработчиками стандартной библиотеки C или в тех случаях, когда он недоступен. Это довольно хорошо описано на его странице руководства:

Описание

brk() устанавливает конец сегмента данных равным значению, указанному в end_data_segment, когда это значение разумно, системе достаточно памяти и процесс не превышает свой максимальный размер данных (см. setrlimit (2)).

sbrk() увеличивает пространство данных программы на байты приращения. sbrk() - это не системный вызов, это просто оболочка библиотеки C. Вызов sbrk() с шагом 0 может быть использован для определения текущего местоположения остановки программы.

Возвращаемое значение

В случае успеха brk() возвращает ноль, а sbrk() возвращает указатель на начало новой области. В случае ошибки возвращается -1, а для errno устанавливается значение ENOMEM.

В заключение,malloc а также free не громоздки - они являются стандартным способом выделения и освобождения памяти в C. Даже если вы хотите реализовать свой собственный распределитель памяти, лучше всего использовать malloc а также free в качестве основы - общий подход заключается в выделении большого куска одновременно с malloc и обеспечить выделение памяти из него (это то, что обычно реализуют субраспределители или пулы)


Re происхождение имени sbrk (или его двоюродный брат brk), это может быть связано с тем, что конец кучи помечен указателем, известным как "break". Куча начинается сразу после сегментов BSS и обычно растет в направлении стека.

Это зависит от того, что вы подразумеваете под malloc как "громоздкий". sbrk обычно больше не используется напрямую, если только вы не реализуете свой собственный распределитель памяти: IE, оператор переопределяет "new". Даже тогда я мог бы использовать malloc, чтобы дать мне первоначальную память.

Если вы хотите узнать, как реализовать malloc() поверх sbrk(), посмотрите http://web.ics.purdue.edu/~cs354/labs/lab6/ который представляет собой упражнение, проходящее через это.

В современной системе вы не должны касаться этого интерфейса. Поскольку вы называете malloc и new громоздкими, я подозреваю, что у вас нет всего необходимого опыта для безопасного и правильного использования sbrk для вашего кода.

Другие вопросы по тегам