Как sbrk/brk реализованы в Linux?

Я думал о том, как ядро ​​Linux реализует системные вызовы, и мне было интересно, может ли кто-нибудь дать мне общее представление о том, как работают sbrk/brk?

Я просмотрел код ядра, но его так много, что я его не понимаю. Я надеялся на резюме от кого-то?


person samoz    schedule 15.06.2009    source источник


Ответы (4)


В представлении очень высокого уровня ядро ​​Linux отслеживает память, видимую процессу, как несколько «областей памяти» (struct vm_area_struct). Существует также структура, которая представляет (опять же в представлении очень высокого уровня) все адресное пространство процесса (struct mm_struct). Каждый процесс (за исключением некоторых потоков ядра) имеет только один struct mm_struct, который, в свою очередь, указывает на все struct vm_area_struct для памяти, к которой он может получить доступ.

Системный вызов sys_brk (находящийся в mm/mmap.c) просто корректирует некоторые из этих областей памяти. (sbrk — это оболочка glibc вокруг brk). Это делается путем сравнения старого значения адреса brk (найденного внутри struct mm_struct) и запрошенного значения.

Было бы проще сначала взглянуть на семейство функций mmap, так как brk является его частным случаем.

person CesarB    schedule 16.06.2009
comment
(sbrk — это оболочка glibc вокруг brk) — мне было трудно найти системный вызов для sbrk. Сейчас нет смысла. - person automaton; 28.07.2015

вы должны понимать, как работает виртуальная память и как отображение MMU связано с реальной оперативной памятью.

реальная оперативная память разделена на страницы, традиционно по 4 КБ каждая. каждый процесс имеет свое собственное отображение MMU, которое предоставляет этому процессу линейное пространство памяти (4 ГБ в 32-разрядной версии Linux). конечно, не все из них фактически выделены. сначала он почти пустой, то есть с большинством адресов не связана никакая реальная страница.

когда процесс сталкивается с незанятым адресом (пытаясь прочитать, записать или выполнить его), MMU генерирует ошибку (аналогично прерыванию) и вызывается система VM. Если он решает, что там должен быть какой-то объем оперативной памяти, он выбирает неиспользуемую страницу оперативной памяти и связывается с этим диапазоном адресов.

Таким образом, ядру все равно, как процесс использует память, а процессу на самом деле все равно, сколько оперативной памяти, у него всегда будет одно и то же линейное 4 ГБ адресного пространства.

теперь brk/sbrk работает на несколько более высоком уровне: в принципе любой адрес памяти «за» этой меткой недействителен и не получит страницу RAM при доступе, вместо этого процесс будет убит. библиотека пользовательского пространства управляет выделением памяти в пределах этого ограничения и только при необходимости просит ядро ​​увеличить его.

Но даже если процесс запускается с установки brk на максимально допустимое значение, он не будет выделять реальные страницы ОЗУ, пока не начнет обращаться ко всем этим адресам памяти.

person Javier    schedule 15.06.2009

Ну, с точки зрения сверхвысокого уровня, ядро ​​​​выделяет страничный блок памяти, изменяет таблицы страниц процесса, запрашивающего этот блок, так что память отображается в пространство виртуальной машины процесса, а затем возвращает адрес.

person Ana Betts    schedule 15.06.2009
comment
Значит, ядро ​​просто хранит где-то структуру данных, в которой говорится, что процессу x принадлежит пространство памяти y? - person samoz; 15.06.2009
comment
каждый процесс имеет свое собственное сопоставление MMU, которое (среди прочего) указывает, какие страницы ему принадлежат. - person Javier; 15.06.2009
comment
Не только ядро ​​— это требуется аппаратно и устанавливается в регистре CR3 каждый раз, когда происходит переключение контекста. - person Ana Betts; 16.06.2009

Ключевая концепция того, как ядро ​​Linux передает память пользовательскому процессу, заключается в том, что доступная для процессов куча (сегмент данных) растет снизу вверх. ядро не отслеживает отдельные блоки памяти, а только непрерывный блок памяти. системные вызовы brk/sbrk расширяют объем памяти, которой обладает процесс, но процесс может управлять ею частями, которые можно использовать.

Ключевым следствием этого является то, что неиспользуемая память, разбросанная по адресному пространству процессов, не может быть возвращена операционной системе для других целей. Только память в самом конце сегмента данных может быть возвращена операционной системе, поэтому используемая память ближе к концу должна быть смещена вниз к началу. На практике почти ни один аллокатор не делает этого. По этой причине обычно важно хорошо управлять максимальным объемом памяти, который использует процесс, потому что это определяет, сколько памяти останется для других процессов.

person SingleNegationElimination    schedule 15.06.2009