| Управление своп-файлом Для хранения образов модифицированных страниц система должна
выделить какое-то пространство на диске. Для этого может использоваться как раздел
диска, так и файл, место для которого выделяется наравне с файлами данных. Большинство
современных систем может использовать как тот, так и другой методы, и поддерживает
динамическое подключение и отключение своп-файлов и своп-разделов. При наличии
в системе нескольких дисков рекомендуется разделить своп-пространство между всеми
(или хотя бы между менее используемыми) дисками. Дело в том, что операции чтения
и записи требуют времени на позиционирование считывающей головки. Пока один накопитель
передвигает головку, второй вполне может передавать данные. Понятно, что линейного
роста производительности с увеличением числа дисков таким способом не получить:
всегда есть вероятность, что все требуемые данные окажутся на одном диске, да
еще и находятся в разных местах, но все равно выигрыш в большинстве случаев оказывается
значительным. В те времена, когда компьютеры были большими, для свопа часто
использовались не диски, а специальные устройства, магнитные барабаны. В отличие
от диска, который имеет одну или, реже, несколько головок чтения-записи, барабан
имел по одной головке на каждую дорожку. Конечно, это повышало стоимость устройства,
но полностью исключало потери времени на позиционирование (рис. 5.23). 
Рис. 5.23. Магнитный диск и магнитный барабан В своп-файл попадают только
страницы, которые изменились с момента загрузки процесса. Если ОС использует абсолютную
загрузку или позиии-онно-независимып код, исполняющийся код не отличается от своего
образа в загрузочном файле, поэтому страницы кода вполне можно подкачивать оттуда,
и нет никакой необходимости копировать их в своп. Часто при загрузке программы
система помещает в память только страницу, на которую указывает стартовый адрес,
а весь остальной используемый код и данные подгружаются механизмом страничного
обмена. При загрузке статически инициализированных данных обычно используется
стратегия copy-on-write (копирование при модификации): первоначально страница
подкачивается из файла. Если она не будет модифицирована и ее объявят жертвой,
то при повторном обращении ее снова подгрузят из того же файла (рис. 5.24). Только
если страница будет изменена, ей выделят место в своп-файле. 
Рис. 5.24. Копирование при модификации Если же используется относительная
загрузка или та или иная форма сборки в момент загрузки (разделяемые библиотеки
или DLL), при загрузке кода происходит перенастройка адресов. В этом случае возможны
два подхода: копировать перенастроенный код в своп или производить перенастройку
заново после каждого страничного отказа. Отображение
файлов в память в Unix Системы семейства Unix предоставляют пользователям
доступ к механизмам, используемым при загрузке программ, в виде системного вызова
гол-ар. Этот вызов отображает участок файла в память. Отображение возможно в двух
режимах: MAP_SHARED изменения в памяти отображаются
в файле— таким образом mmap можно использовать для реализации разделяемой памяти
и MAP_PRIVATE (соответственно, изменения памяти в файле
не отображаются — при этом измененные страницы копируются в своп-файл). Широко
используется выделение памяти при помощи отображения псевдофайла /dev/zero (файл
бесконечной длины, состоящий из одних нулей) в память в режиме
MAP_PRIVATE. Даже когда место под своп-файл выделяется динамически,
система обычно предоставляет возможность ограничивать его рост. У интерактивных
систем при приближении к границе емкости своп-файла система часто начинает
выдавать предупреждения пользователю. Однако основным видом реакции на переполнение
или превышение лимитов роста своп-файла является отказ выделять память прикладным
программам. Поэтому грамотно написанные программы всегда должны проверять, нормально
ли завершился запрос на выделение памяти, и по возможности разумно обрабатывать
ненормальное завершение. Это нужно не только в том случае, когда программа будет
переноситься в систему без виртуатьной памяти, но и во вполне штатной (хотя и
относительно редкой) ситуации переполнения свопа. Иногда, впрочем, система
может выделять память (точнее, не память, а только адресное пространство)
программам без оглядки на то, сколько есть свободного свопа. Эта довольно опасная
стратегия, называемая overcommit, на первый взгляд кажется бессмысленной или полезной
только в очень специальных случаях, например при использовании разреженных массивов.
В действительности эта стратегия оправдана и тогда, когда мы можем быть уверены,
что большинство выделенных процессу страниц никогда не будут использованы, например,
при широком применении стратегии copy-on-write. Overcommit
в Unix В системах семейства Unix копирование при записи применяется
не только при загрузке сегментов данных программ и отображений файлов в память,
но и при создании задач. Системный вызов fork (подробнее обсуждался в главе 3)
создает полную копию адресного пространства процесса, выполнившего этот вызов.
Физического копирования, естественно, не происходит. Вместо этого система отображает
память родительского процесса в адресное пространство потомка и устанавливает
защиту от записи на все страницы обеих задач. Когда какая-то из задач пытается
осуществить запись, соответствующая страница физически копируется и запись осуществляется
уже в копию. Большинство порожденных задач исполняют системный вызов exec вскоре
после создания, изменив лишь несколько переменных в своем адресном пространстве.
При таком стиле работы с памятью, действительно, многие выделяемые страницы не
используются никогда, а большинство из используемых только прочитываются, поэтому
overcommit является стандартной стратегией выделения памяти в Unix. |