Как работает 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 для вашего кода.