Память ядра
Если процессу необходимо получить некоторое количество страниц, ядро отберет их из числа свободных. При освобождении страниц ядро снова возвратит их в список. При этом фактическое расположение страниц в памяти компьютера не важно. Работа с памятью на уровне страниц реализована в системе 4.3BSD путем применения процедур memall() и memfree(), в системе SVR4 для этой цели применяются процедуры get_page() и freepageQ. Такой подход упрощает задачу выделения памяти. С этой целью ядро поддерживает связанный список свободных страниц.
Распределитель памяти страничного уровня (page-level allocator) имеет два принципиально важных клиента (см. рис. 12.1). Один из них называется страничной подсистемой (paging system) и представляет собой часть виртуальной системы памяти. Он производит выделение памяти для прикладных процессов, размещая страницы в их адресном пространстве. Во многих системах UNIX страничная система также управляет страницами, используемыми под дисковые буферы блоков. Другим клиентом является распределитель памяти ядра (kernel memory allocator), предоставляющий буферы памяти разного размера для множества подсистем ядра. Чаще всего ядру необходимы области памяти различной длины на короткие промежутки времени.
Ниже перечислены несколько задач, использующих память ядра.
♦ Процедура преобразования полного имени может запрашивать буфер (обычно размером 1024 байта) в целью копирования полного имени из пользовательского адресного пространства.
♦ Процедура allocbQ выделяет буферы STREAMS произвольных размеров.
♦ Во многих реализациях системы UNIX в памяти размещаются структуры zombie, в которых находится информация о статусе выхода и использовании ресурсов завершенных процессов.
♦ В SVR4 ядро инициирует многие объекты (структуры ргос, объекты vnode, блоки дескрипторов файлов и т. д.) динамически по мере необходимости.
Большинство таких запросов требуют памяти в меньшем объеме, чем размер одной страницы, следовательно, применение распределителя памяти ядра для таких задач является неподходящим. Для выделения памяти более мелкими порциями необходимо использовать другой механизм. Простейшим решением проблемы является запрещение динамического выделения памяти [1]. В ранних реализациях UNIX использовались таблицы фиксированного размера для объектов vnode, структур ргос и т. д. Если в таких системах запрашивалась память для временного хранения полных имен или сетевых сообщений, ядро выделяло для них буферы из буферного кэша. Кроме этого, в отдельных ситуациях применялись непредусмотренные изначально (ad hoc) схемы выделения памяти, например в драйверах терминалов использовались clists.