Распределение памяти ядра
Ядро в процессе работы часто генерирует и уничтожает маленькие таблицы и буфера, память для каждого из которых выделяется динамически. В [VAHA96] перечислены следующие примеры.
• Преобразование имени пути может запросить буфер для копированияимени из пользовательского пространства.
• Подпрограмма allocb ( ) выделяет буфера произвольного размера.
• Ряд реализации UNIX выделяют "зомби"-структуры для хранения информации о состоянии выхода и использовании ресурсов завершенными процессами.
• В SVR4 и Solaris ядро динамически распределяет множество объектов (таких, как структуры процессов, блоки дескрипторов файлов и др.).
Размер большинства этих блоков гораздо меньше типичного размера страницы памяти и, соответственно, использование страничного механизма в данном случае крайне неэффективно. В SVR4 используется модификация системы двойников (описанной в разделе 7.2).
Стоимость выделения свободногоблока памяти в системе двойников меньше, чем в случае использования стратегий первого или наилучшего подходящего [KNUT97]. Однако при управлении памятью ядра выделение и освобождение памяти должно выполняться с максимально возможной скоростью. Недостатком же системы двойников являются затраты времени на разделение и слияние блоков.
Беркли (Barkley) и Ли (Lee) из AT&T предложили модификацию, известную как "ленивая" система двойников [BARK89], которая принята в SVR4. Авторами замечено, что UNIX часто демонстрирует устойчивое состояние памяти ядра, т.е. количество требующихся блоков определенного размера мало меняется со временем. Таким образом, вполне возможна ситуация, когда освобождающийся блок размером 2i сливается со своим двойником в блок размером 2i+1, который тут же вновь разделяется на два блока размером 2i в соответствии с запросом системы. Чтобы избежать излишних слияний и разделений блоков, слияние освобожденных блоков откладывается до того момента, когда оно оказывается действительно необходимым (и тогда производится максимально возможное количество слияний блоков).
В модифицированной таким образом системе двойников используются следующие параметры:
Ni — текущее количество блоков размером 2i;
Ai — текущее количество занятых блоков размером2i;
Gi — текущее количество глобально свободных блоков размером 2i (Это блоки, пригодные для слияния со своими двойниками. Когда двойник такого блока становится глобально свободным, эти два блока сливаются в глобально свободный блок размером 2i+1. Все свободные блоки в системе двойников могут рассматриваться как глобально свободные);
Li — текущее количество локально свободных блоков размером2i (Это блоки, не пригодные для слияния. Даже если двойник такогоблока становится свободным, эти два блока не сливаются, а остаются в ожидании последующих запросов на блоки данного размера.).
Выполняется следующее соотношение:
Ni= Ai+ Gi+ Li
В целом данная система двойников пытается поддерживать пул локально свободных блоков и производит слияние, только когда количество локально свободных блоков превышает предопределенный порог (при наличии слишком большого количества локально свободных блоков возрастает вероятность недостатка блоков большего размера для удовлетворения требований системы). В основном при освобождении блока слияние не выполняется, что минимизирует накладные расходы. Никаких различий между локально и глобально свободными блоками при выделении блока в ответ на запрос системы не делается.
Для слияния используется критерий, согласно которому количество локально свободных блоков данного размера не должно превышать количество занятыхблоков этого размера (т.е. должно выполняться условие Li < Аi). Это вполне разумный принцип для ограничения количества локально свободных блоков; эксперименты, описанные в [BARK89], подтверждают, что такая схема приводит к значительному снижению стоимости распределения памяти.
Для реализации описанной схемы ее авторы определили переменную задержки Di = 4 – Li = Ni - 2Li –Gi . Алгоритм схемы приведен в листинге 8.1.
Листинг 8.1. Алгоритм "ленивой" системы двойников
Начальное значение Di равно 0
После выполнения операций значение Di изменяется следующим образом:
(I) Если следующая операция является запросом на выделение блока:
Если имеется свободный блок, выбрать его
Если выбранный блок локально свободен, Di: = Di+2 иначе Di = Di+2.
в противном случае получить два блока путем разделения большего блока на два меньших (рекурсивная операция).
Выбрать один из них, пометив второйкак локально свободный.
Di остается неизменным (при этом значение Di для других размеров блоков может измениться в связи с использованием рекурсивности).
(II). Если следующая операция — запрос на освобождение блока
При Di 2
Пометить блок как локально свободный и освободить его локально
Di = Di- 2
При Di =1
Пометить блок как глобально свободный и освободить его глобально; если это возможно - выполнить слияние блоков.
Di := 0
При Di = 0
Пометить блок как глобально свободный и освободить его глобально; если это возможно - выполнить слияние блоков.
Выбрать один локально свободный блок размером 2i и освободить его глобально; если это возможно, выполнить слияние блоков.
Di := 0
Дата добавления: 2016-06-05; просмотров: 1693;