Как sbrk / brk реализован в Linux? - PullRequest
19 голосов
/ 15 июня 2009

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

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

Ответы [ 4 ]

23 голосов
/ 17 июня 2009

В режиме очень высокого уровня ядро ​​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 является его частным случаем.

18 голосов
/ 15 июня 2009

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

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

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

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

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

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

4 голосов
/ 15 июня 2009

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

2 голосов
/ 15 июня 2009

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

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

...