ТЕХНИКА ОПТИМИЗАЦИИ ПРОГРАММ

Иерархия оперативной памяти


Оперативная память… что это? Объект материального мира или абстракция, не соответствующая никакой физической действительности? Не спешите отвечать. Давайте рассуждать логически. Если, вооружившись отверткой, открутить несколько болтов, удерживающих корпус компьютера, то, среди прочего семейства микросхем, на материнской плате обнаружатся один, два или три вертикально установленных прямоугольных модуля. Это и есть оперативная память или, говоря по-английски, RAMRandom Access Memory (Память с Произвольным Доступом). Значит, оперативная память – это некоторое физическое устройство (какое – уже неважно). Так?

А вот попробуйте подойти с этим вопросом к любому программисту. Если наш программист не будет пьян или вусмерть укурен, то, скорее всего, он определит память как совокупность ячеек, причем не хаотично разбросанных точно пшено на асфальте, а объединенных адресным пространством с наперед заданными свойствами. Слышите? Ни слова об устройстве! Причем, это был явно системный программист, который, если захочет, может без труда положить значение 0x666 в ячейку под "номером" 0x999, а спустя некоторое время извлечь его оттуда. Прикладные же программисты имеют крайне смутное представление о том как нумеруются ячейки (и нумеруются ли они вообще). Языки высокого уровня приучают оперировать не ячейками, а переменными. Считается, что переменные располагаются в памяти, вернее каждое переменной соответствует одна или более ячеек памяти. На самом же деле это не совсем так (или даже совсем не так)! Компилятору может взбрести в голову разместить переменных в регистрах или же вовсе не размещать их нигде, если он обнаружит, что значение переменной в программе не используется или же его можно вычислить еще на этапе компиляции.

Так что же все-таки представляет собой оперативная память? С точки зрения сборщика компьютеров, память – это микросхема. С точки зрения программиста – абстрактное хранилище данных. И бессмысленно спрашивать кто из них прав! Они оба… не правы.
Оперативная память – не микросхема и не абстракция. Это целая подсистема

компьютера, состоящая из множества взаимодействующих друг другом физических компонентов, образующих сложную иерархию логических абстракций.

>>>>> врезка

Давным-давно, когда компьютеры обходились без операционной системы, а о многозадачности никто и не слышал, загружать программы приходилось вручную, зато каждая из них монопольно владела всеми ресурсами компьютера, в том числе и оперативной памятью.

С появлением многозадачных систем встала проблема разделения ресурсов (в первую очередь – оперативной памяти) между несколькими приложениями и, что тоже немаловажно, защиты "владений" одного приложения от случайных или преднамеренных воздействий других. Были и другие трудности. В частности, требовалось обеспечить независимость работы приложений от адреса загрузки и каким-то образом исхитрится втиснуть множество одновременно выполняющихся программ в ограниченный объем оперативной памяти.

Решение этих задач потребовало создание многоуровневой иерархии организации памяти, в результате чего непосредственный доступ к ней оказался утрачен.

<<<<< 

Абстракции хороши тем, что уменьшают минимально необходимое количество знаний для работы с аппаратурой, ликвидируя целый пласт второстепенных архитектурных особенностей. Так, знаете ли вы, что чтение ячейки динамической памяти разрушает ее содержимое и этого никто не замечает лишь только потому, что система автоматически восстанавливает информацию, самостоятельно выполняя запись данных после завершения операции чтения.

Второе полезное свойство абстракций: без них все программы были бы непереносимы. Абстракции реализуют (или, если так угодно, – эмулируют) виртуальную машину, устраняя (или по крайней мере ослабляя) влияние конструктивных особенностей физического оборудования на алгоритм реализации программы.



Стоп! Мы слишком увлеклись! Если мы не будет протирать звезды, пардон, учитывать особенности физического оборудования, то кто же тогда их будет учитывать?! Навряд ли этим займутся уровни абстракций и уж тем более – не само оборудование! Эмуляция и производительность – понятия несовместимые…



Абстрактная оперативная память однородна, физическая память – нет. Абстрактная модель оперативной памяти не имеет абсолютно никаких представлений о тех многочисленных ловушках и конструктивных ограничениях, которые словно терьеры вцепляются в программиста, препятствуя достижению максимального быстродействия. Чтобы победить в этой борьбе, нам придется последовательно "обезвредить" все слои абстракции и выйти на уровень "голого" физического оборудования.

Маленькая деталь. Сказанное вовсе не означает, что вам придется программировать на ассемблере и взаимодействовать с "железом" напрямую. Достаточно лишь планировать запросы к памяти с учетом характера этого железа, а эффективно программировать можно на любом языке. Если Вам направиться Си/С++, Паскаль или даже Perl, – я не буду ни в чем вас ограничивать.

Можно провести такую аналогию. Допустим, выемка писем из почтового ящика осуществляется каждое утро ровно в девять часов. Следовательно, для ускорения переписки мы должны обязательно отправлять наши письма до девяти. Даже незначительное опоздание увеличит срок доставки письма на целые сутки! Надеюсь, это вас убедит, что снять крышку с черного ящика с надписью "подсистема оперативной памяти IBM PC" все таки полезно. ОК, снимаем… (тяжелая зараза!) Еще одна секунда и мы узнаем, что же находится там…

На вершине иерархии (см. рис. sx1) находятся прикладные библиотеки управления памятью, реализующие унифицированный интерфейс к сервисам менеджера куч (heap manager) операционной системы. (Вообще-то, некоторые операционные системы, в частности MS-DOS, не имеют полноценного менеджера куч, и в этом случае его обязанности целиком ложатся на плечи прикладной библиотеки, но о таких "операционных системах" мы говорить не будем, поскольку это совершенно другая тема).

Менеджер куч (или, иначе говоря, менеджер динамической памяти), обеспечивает поддержку базовых операции с блоками памяти (выделение блока памяти, освобождение блока памяти, изменение размеров выделенного блока и т.д.)



Уровнем ниже лежит менеджер виртуальной памяти (virtual memory manager), который в тесной координации с процессором реализует:

a)       виртуальные адресные пространства, т.е. абстрагируется от реальных физических адресов и позволяет назначать ячейкам памяти произвольные адреса. Благодаря этому, множество одновременно запущенных приложений могут быть загружены по одним и тем же логическим (виртуальным) адресам, причем адресные пространства этих приложений не будет пересекаться! Приложения, словно жители параллельных миров, при всем желании не "увидят" друг друга, конечно, если не воспользуются специально созданными для этой цели разделяемыми регионами памяти или другими средствами межпроцессорного взаимодействия, но это – разговор особый.

b)       виртуальную память, представляющую собой дальнейшее развитие идей виртуальных адресных пространств. Любая ячейка виртуальной памяти может находиться как в оперативной памяти, так и на дисковом накопителе. Это позволяет выделять практически неограниченные объемы памяти, вплоть до десятков гигабайт (на самом деле, ОС семейства Windows предоставляют в распоряжение каждого процесса максимум два гигабайта, разве что Windows NT Server Enterprise не накладывает на аппетит программиста никаких ограничений, см. описание "Very Large Memory" в Platform SDK).

Функции менеджера виртуальной памяти требуют для своей работы определенных привилегий, поскольку непосредственно взаимодействуют с центральным процессором и драйвером диска.

Процессор же, в свою очередь, общается с памятью и диском не напрямую, а через контроллер памяти и дисковый контроллер соответственно. Оба в современных компьютерах интегрированы в так называемый чипсет (Chipset – набор микросхем, так же называемый "набором системной логики"), от интеллектуальности которого во многом зависит производительность всей системы.

Основная оперативная память персональных компьютеров обычно реализуется на весьма медленных (по сегодняшним меркам) микросхемах динамической памяти.


Поэтому, внутри процессора размешается небольшое количество быстродействующей сверхоперативной памяти, ускоряющей доступ к интенсивно используемым данным.

Сверхоперативная память, так же именуемая кэш-памятью, формально прозрачна для программиста: она не входит в адресное пространство, ее содержимое не может быть непосредственно прочитано или изменено.

Управление сверхоперативной памятью осуществляется не процессором, а кэш-контроллером

(впрочем, на современных процессорах кэш-контроллер интегрирован в сам процессор, но сути дела это не меняет). В служебные обязанности кэш-контроллера в первую очередь входит накопление в сверхоперативной памяти действительно нужных данных и удаление оттуда всякого "мусора", – данных, которые более не понадобятся.

Итого, иерархия подсистемы оперативной памяти имеет как минимум семь уровней абстракций, каждый из которых реализуется "своей" аппаратурой. Каждый уровень иерархии в свою очередь делится на несколько подуровней. Так, например, чипсет включает в себя блок интерфейса с шиной, арбитр запросов, несколько очередей запросов, контроллер памяти, буфер обмена и т.д.

Поэтому, воспринимайте схему sx1 не более чем наброском, грубо очерчивающим наш дальнейший маршрут путешествия по подсистеме памяти…



Рисунок 3 sx1.doc 0х22 Иерархия памяти в операционных системах Windows 9x/NT/2000 и UNIX (грубо)


Содержание раздела