Планировщик задач в ядре заботиться о разделении времени между процессами. Ваша опрерационная система также разделяет их в пространстве рабочей памяти так, что один процесс не мешает другому. Раз вы используете программы совместно, вы бы не хотели, чтобы ошибка в одной из них могла нарушить работу остальных. Чтобы решить эту проблему операционная система осуществляет вещи, называемые управление памятью (memory management).
Каждый процесс в вашем зоопарке нуждается в своей собственной области памяти, в этом месте содержится выполняемый код этой программы, хранятся переменные и результаты вычислений. Вы можете думать о ней как о наборе состоящем из сегментов кода (code segment) (содержащих инструкции порцессору для выполнения программы), из них осуществляется только чтение; и сегментов данных (data segment) (хранилище переменных и данных процесса), в них можно осуществлять и запись и чтение. Сегменты данных действительно уникальны для каждого процесса, но если два процесса используют один и тот же программный код, Unix в качестве эффективной меры, автоматически организовывает их для использования единого сегмента кода.
Эффективность важна, потому что память дорогостоящий ресурс. Иногда вам может ее не хватать, чтобы полностью разместить все запущенные на машине программы, особенно если вы используете большие программы как X-сервер. Чтобы обойти это, Unix использует технику получившую название виртуальная память (virtual memory). Она не пытается держать весь код и данные процесса в памяти. Вместо этого она хранит только отоносительно небольшие рабочие наборы (working set); полностью код и даннные процессов находятся в специальной области подкачки (swap space) на вашем жестком диске.
Стоит отметить, что в прошлом, "Иногда" употребленное в предыдущем параграфе было "Почти всегда" — обычно размер памяти был меньше, чем размер выполняемых программ, так что своппинг был частым. В наши дни память гораздо менее дорогостоящая и даже машины нижней ценовой категории имеют ее в достаточном объеме. На современных однопользовательских машинах с объемом памяти 64 Мб и выше, можно запускать X-сервер и делать типичную работу без обращений к области подкачки после того как программы загружены в память.
Предыдущий раздел описывает вещи несколько упрощенно. Да, программы видят большую часть памяти как плоский банк адресов, много больший чем физически доступная память, и подкачка с диска (disk swapping) используется для поддержания этой иллюзии. Однако, ваше аппаратное обеспечение имеет в себе не менее пяти разных типов памяти, и разница между ними может иметь большое значение при настройке программы для работы на максимальной скорости. Чтобы по-настоящему понять, что происхрдит в вашей машине, стоит изучить как все это работает вместе.
Существует пять типов памяти: регистры процессора, внутренний (on-chip) кэш процессора, внешний кэш (off-chip), основаная память и жесткий диск. И причина по которой они все существуют проста: скорость стоит денег. Я перечисл эти типы памяти в порядке возрастания времени доступа (скорости работы) и в порядке убывания стоимости. Регистровая память быстрейшая и наиболее дорогая, произвольный доступ к ней может выполняться миллиард раз в секунду, в то время как память на жестком диске самая медленная и дешевая, и при произвольном доступе достигается скорость около 100 обращений в секунду.
Вот список скоростей начала 21 века, отражающий типичную настольную машину. В то время как скорости и объемы меняются, а цены становятся ниже, пропорции между видами памяти остаются достаточно постоянными и очерчивают образ иерархии памяти.
Размер: 13000 Мб Скорость доступа: 100 Кб/сек
Размер: 256 Мб Скорость доступа: 100 Мб/сек
Размер: 512 Кб Скорость доступа: 250 Мб/сек
Размер: 32 Кб Скорость доступа: 500 Мб/сек
Размер: 28 байт Скорость доступа: 1000 Мб/сек
Мы не можем построить всю систему с использованием только самой быстрой памяти. Это будет очень дорого — даже если это не так, быстрая память непостоянна. Именно, она теряет весь свой блеск и приемущества когда мы выключаем компьютер. Поэтому компьютеры имеют жесткие диски или другие устройства постоянного хранения данных, на которых те и содержаться после выключения питания. И здесь имеем огромное несоответствие между скоростью процессоров и жестких дисков. Три средних уровня иерарахии памяти: внутренний кэш (internal cache), внешний кэш (external cache) и основная память существуют, чтобы заполнить эту брешь.
Linux и другие Unix имеют функциональное средство называемое виртуальной памятью (virtual memory). Что позволяет операционной системе работать с намного большим объемом основной памяти, чем имеется фактически. Ваша действительная физическая память работает как набор окон или кэшей ведущих к гораздо большему пространству "виртуальной" памяти, большая часть которой на самом деле расположена в специальной области подкачки (swap area) на диске. Скрывая механизм реализации этой иллюзии от взгляда программ пользователя, ОС перемещает блоки данных (называемых "страницами" ("pages")) между памятью и диском. Конечным результатом этих ухищрений являеится то, что ваша виртуальная память намного больше, но не намного медлеенее, чем реальная память.
Насколько виртуальная память медленей физической зависит от того, насколько хорошо алгоритмы своппинга операционной системы соответствуют способу ваших программ использовать виртуальнуюю память. Здесь есть благоприятный момент, в том что чтение и запись памяти близки по врмени, это ведь к созданию группы блоков (кластеров (cluster)) в пространстве памяти. Это тенденция называется локальность (locality), или более формально локальные ссылки (locality of reference) — и это хорошая штука. Если ссылки на адреса в памяти прыгают по виртуальному пространству беспорядочно, то будет осуществляться чтение и запись диска для каждой новой ссылки, и ваша виртуальная память будет такой же медленной как и диск. Но, из-за того что, программы преимущественно демонстрируют локальность ссылок, ваша операционная система может делать сравнительно малое количество подкачек относительно числа ссылок.
Опытным путем было установлено, что наиболее эффективный метод для широкого класса моделей использования памяти, очень прост; он называется LRU или "least recently used" (наименее востребованы) алгоритм. Система виртуальной памяти по мере надобности извлекает блоки данных с диска в свои рабочие наборы (working set). Когда физической памяти становится недостаточно для рабочих наборов, она сбрасывает те из них которые были наименее востребованы. Все Unix, и большинство других операционных систем использующих виртуальную память, используют незначительно измененный LRU.
Виртуальная память это первая часть моста между скоростью диска и процесса. Она явно управляется ОС. Однако, все еще существует большая пропасть между скоростью физичекой памяти и скоростью, с которой процессор имеет доступ к памяти собственных регистров. Внешний и внутренний кэш направлены на решние этой задачи, используя технику подобную виртуальной памяти, которую я уже описал.
Как физическая память в роли окон или кэшей для области подкачки на диске, так и внешний кэш выступает как окна в основную память. Внешний кэш быстрее (250 Мб/сек конечно быстрее 100 Мб/сек) и меньше. Аппаратный контроллер памяти использует алгоритм LRU во внешнем кэше приминительно к блокам данных расположенных в основной памяти. По историческим причинам, единицей своппинга в кэше называется строка (line), а не страницей.
Но мы еще не закончили. Внутренний кэш кэшируя порции данных из внешнего позволяет нам сделать последний шаг к действительно эффективной скорости. Он еще быстрее и меньше, в действительности он живет прямо в процессоре.
Если вы хотите сделать ваши программы по-настоящему быстрыми, полезно будет знать следующие подробности. Ваши программы выполняются быстрее, когда они обладают сильной локальностью, потому что это улучшает кэширование. Теоретически, легчаший путь создавать быстрые программы, это делать их маленькими. Если программа не замедляется большим количеством обращений к диску или ожиданием событий из сети, она обычно работает на скорости наименьшего кэша в котором умещается.
Если вы не можете сделать всю вашу программу небольшой, попытайтесь в критичных по скорости выполнения ее частях использовать локальные ссылки. Рассмотрение деталей данной техники лежат за пределами рассмотрения этого руководства; к тому времени когда вам это понадобится вы уже будете хорошо знакомы с каким-нибудь компилятором и сможете сами найти необходимую информацию.
Сейчас когда вы имеете достаточно физической памяти, чтобы практически не использовать своппинг, часть операционной системы называемой менеджер памяти (memory manager) продолжает выполнять важную работу. Он следит затем, чтобы программы могли изменять только свои собственные сегменты данных, это предотвращает выполнение неправильного или злонамеренного кода одной программы по копанию в данных другой программы. Для осуществления этой задачи он хранит таблицы сегментов кода и данных. Таблицы обновляются всякий раз когда процесс запрашивает выделение памяти или освобождает ее (в последнем случае, обычно когда завершает работу).
Эта таблица используется для передачи команд специализированной части аппаратного обеспечения называемой MMU или memory management unit (модуль управления памятью). Современные процессоры имеют встроенные в них MMU. MMU используют специальную способность включать ограждение вокруг областей памяти, так ссылка выходящая за допустимые пределы будет отклонена и вызовется специальное прерывание.
Если вы когда либо видели сообщение Unix, которое гласило "Segmentation fault", "core dumped" или что-то подобное, именно это и произошло; выполняемая программа попыталась обратиться к памяти вне своего сегмента, что вызвало неизбежное прерывание. Это указывает на ошибку в программном коде; core dump оставляет после себя информацию помогающую программисту диагностировать и найти ее.
Есть и другая причина для защиты процессов друг от друг, изоляцией памяти к которой они имеют доступ. Вы хотите иметь возможность контролироваь их доступ к файлам, таким образом чтобы глючная или злобная программа не могла повредить критично важные части системы. Вот почему в Unix есть права доступа к файлам (file permissions), которые мы обсудим ниже.