Выбрать главу

 unsigned long        private;

 struct address_space *mapping;

 pgoff_t              index;

 struct list_head     lru;

 void                 *virtual;

};

Рассмотрим самые важные поля этой структуры. Поле flags содержит состояние страницы. Это поле включает следующую информацию: является ли страница измененной (dirty) или заблокированной (locked) в памяти. Значение каждого флага представлено одним битом, поэтому всего может быть до 32 разных флагов. Значения флагов определены в файле <linux/page-flags.h>.

Поле _count содержит счетчик использования страницы — т.е. сколько на эту страницу имеется ссылок. Когда это значение равно нулю, это значит, что никто не использует страницу, и она становится доступной для использования при новом выделении памяти. Код ядра не должен явно проверять значение этого поля, вместо этого необходимо использовать функцию page_count(), которая принимает указатель на структуру page в качестве единственного параметра. Хотя в случае незанятой страницы памяти значение счетчика _count может быть отрицательным (во внутреннем представлении), функция page_count() возвращает значение нуль для незанятой страницы памяти и положительное значение — для страницы, которая в данный момент используется. Страница может использоваться страничным кэшем (в таком случае поле mapping указывает на объект типа address_space, который связан с данной страницей памяти), может использоваться в качестве частных данных (на которые в таком случае указывает поле private) или отображаться в таблицу страниц процесса.

Поле virtual — это виртуальный адрес страницы. Обычно это просто адрес данной страницы в виртуальной памяти ядра. Некоторая часть памяти (называемая областью верхней памяти, high memory) не отображается в адресное пространство ядра (т.е. не входит в него постоянно). В этом случае значение данного поля равно NULL и страница при необходимости должна отображаться динамически. Верхняя память будет рассмотрена в одном из следующих разделов.

Наиболее важный момент, который необходимо понять, это то, что структура page связана со страницами физической, а не виртуальной памяти. Поэтому то, чему соответствует экземпляр этой структуры, в лучшем случае, очень быстро изменяется. Даже если данные, которые содержались в физической странице, продолжают существовать, то это не значит, что эти данные будут всегда соответствовать одной и той же физической странице памяти и соответственно одной и той же структуре page, например из-за вытеснения страниц (swapping) или по другим причинам. Ядро использует эту структуру данных для описания всего того, что содержится в данный момент в странице физической памяти, соответствующей данной структуре. Назначение этой структуры— описывать область физической памяти, а не данных, которые в ней содержатся.

Ядро использует рассматриваемую структуру данных для отслеживания всех страниц физической памяти в системе, так как ядру необходима информация о том, свободна ли страница (т.е. соответствующая область физической памяти никому не выделена). Если страница не свободна, то ядро должно иметь информацию о том, чему принадлежит эта страница. Возможные обладатели: процесс пространства пользователя, данные в динамически выделенной памяти в пространстве ядра, статический код ядра, страничный кэш (page cache) и т.д.

Разработчики часто удивляются, что для каждой физической страницы в системе создается экземпляр данной структуры. Они думают: "Как много для этого используется памяти!" Давайте посмотрим, насколько плохо (или хорошо) расходуется адресное пространство для хранения информации о страницах памяти. Размер структуры struct page равен 40 байт. Допустим, что система имеет страницы размером 1 Кбайт, а объем физической памяти равен 128 Мбайт. Тогда все структуры раде в системе займут немного больше 1 Мбайт памяти — не очень большая плата за возможность управления всеми страницами физической памяти.

Зоны

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

• Некоторые аппаратные устройства могут выполнять прямой доступ к памяти (ПДП, DMA, Direct Memory Access) только в определенную область адресов.

• На некоторых аппаратных платформах для физической адресации доступны большие объемы памяти, чем для виртуальной адресации. Следовательно, часть памяти не может постоянно отображаться в адресное пространство ядра.

В связи с этими ограничениями, в операционной системе Linux выделяют три зоны памяти.

• ZONE_DMA. Содержит страницы, которые совместимы с режимом DMA.

• ZONE_NORMAL. Содержит страницы памяти, которые отображаются в адресные пространства обычным образом.

• ZONE_HIGHMEM. Содержит "верхнюю память", состоящую из страниц, которые не могут постоянно отображаться в адресное пространство ядра.

Эти зоны определяются в заголовочном файле <linux/mmzone.h>.

То, как используется разделение памяти на зоны, зависит от аппаратной платформы. Например, для некоторых аппаратных платформ нет проблем с прямым доступом к памяти ни по какому адресу. Для таких платформ зона ZONE_DMA является пустой, и для всех типов выделения памяти используется зона ZONE_NORMAL.

Как противоположный пример можно привести платформу x86, для которой устройства ISA[61] не могут выполнять операции DMA в полном 32-разрядном пространстве адресов, так как устройства ISA могут обращаться только к первым 16 Мбайт физической памяти. Следовательно, зона ZONE_DMA для платформы x86 содержит только страницы памяти с физическими адресами в диапазоне 0-16 Мбайт.

Аналогично используется и зона ZONE_HIGHMEM. To, что аппаратная платформа может отображать и чего она не может отображать в адресное пространство ядра, отличается для разных аппаратных платформ. Для платформы x86 зона ZONE_HIGHMEM — это вся память, адреса которой лежат выше отметки 896 Мбайт. Для других аппаратных платформ зона ZONE_HIGHMEM пуста, так как вся память может непосредственно отображаться. Память, которая содержится в зоне ZONE_HIGHMEM, называется верхней памятью[62] (high memory). Вся остальная память в системе называется нижней памятью (low memory).

Зона ZONE_NORMAL обычно содержит все, что не попало в две предыдущие зоны памяти. Для аппаратной платформы x86, например, зона ZONE_NORMAL содержит всю физическую память от 16 до 896 Мбайт. Для других, более удачных аппаратных платформ, ZONE_NORMAL — это вся доступная память. В табл. 11.1 приведен список зон для аппаратной платформы x86.

Таблица 11.1. Зоны памяти для аппаратной платформы x86

Зона Описание Физическая память
ZONE_DMA Страницы памяти, совместимые с ПДП < 16 Мбайт
ZONE_NORMAL Нормально адресуемые страницы 16 - 896 Мбайт
ZONE_HIGHMEM Динамически отображаемые страницы > 896 Мбайт
вернуться

61

Некоторые некачественные устройства PCI также могут выполнять прямой доступ к памяти только к 24-битовом адресном пространстве. Но эти устройства работают не правильно.

вернуться

62

Это не имеет ничего общего с верхней памятью в операционной системе DOS.